nautilus-3.6.3/libnautilus-private/nautilus-canvas-container.c

No issues found

   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
   2 
   3 /* nautilus-canvas-container.c - Canvas container widget.
   4 
   5    Copyright (C) 1999, 2000 Free Software Foundation
   6    Copyright (C) 2000, 2001 Eazel, Inc.
   7    Copyright (C) 2002, 2003 Red Hat, Inc.
   8    
   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.
  13 
  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.
  18 
  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.
  23 
  24    Authors: Ettore Perazzoli <ettore@gnu.org>,
  25    Darin Adler <darin@bentspoon.com>
  26 */
  27 
  28 #include <config.h>
  29 #include <math.h>
  30 #include "nautilus-canvas-container.h"
  31 
  32 #include "nautilus-global-preferences.h"
  33 #include "nautilus-canvas-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>
  42 
  43 #include <gdk/gdkkeysyms.h>
  44 #include <gtk/gtk.h>
  45 #include <gdk/gdkx.h>
  46 #include <glib/gi18n.h>
  47 #include <stdio.h>
  48 #include <string.h>
  49 
  50 #define DEBUG_FLAG NAUTILUS_DEBUG_CANVAS_CONTAINER
  51 #include "nautilus-debug.h"
  52 
  53 #define TAB_NAVIGATION_DISABLED
  54 
  55 /* Interval for updating the rubberband selection, in milliseconds.  */
  56 #define RUBBERBAND_TIMEOUT_INTERVAL 10
  57 
  58 #define RUBBERBAND_SCROLL_THRESHOLD 5
  59 
  60 /* Initial unpositioned icon value */
  61 #define ICON_UNPOSITIONED_VALUE -1
  62 
  63 /* Timeout for making the icon currently selected for keyboard operation visible.
  64  * If this is 0, you can get into trouble with extra scrolling after holding
  65  * down the arrow key for awhile when there are many items.
  66  */
  67 #define KEYBOARD_ICON_REVEAL_TIMEOUT 10
  68 
  69 #define CONTEXT_MENU_TIMEOUT_INTERVAL 500
  70 
  71 /* Maximum amount of milliseconds the mouse button is allowed to stay down
  72  * and still be considered a click.
  73  */
  74 #define MAX_CLICK_TIME 1500
  75 
  76 /* Button assignments. */
  77 #define DRAG_BUTTON 1
  78 #define RUBBERBAND_BUTTON 1
  79 #define MIDDLE_BUTTON 2
  80 #define CONTEXTUAL_MENU_BUTTON 3
  81 #define DRAG_MENU_BUTTON 2
  82 
  83 /* Maximum size (pixels) allowed for icons at the standard zoom level. */
  84 #define MINIMUM_IMAGE_SIZE 24
  85 #define MAXIMUM_IMAGE_SIZE 96
  86 
  87 #define ICON_PAD_LEFT 4
  88 #define ICON_PAD_RIGHT 4
  89 #define ICON_BASE_WIDTH 96
  90 
  91 #define ICON_PAD_TOP 4
  92 #define ICON_PAD_BOTTOM 4
  93 
  94 #define CONTAINER_PAD_LEFT 4
  95 #define CONTAINER_PAD_RIGHT 4
  96 #define CONTAINER_PAD_TOP 4
  97 #define CONTAINER_PAD_BOTTOM 4
  98 
  99 #define STANDARD_ICON_GRID_WIDTH 155
 100 
 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
 106 
 107 #define MINIMUM_EMBEDDED_TEXT_RECT_WIDTH       20
 108 #define MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT      20
 109 
 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
 112  */
 113 #define ICON_SIZE_FOR_LARGE_EMBEDDED_TEXT 55
 114 
 115 #define SNAP_HORIZONTAL(func,x) ((func ((double)((x) - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X) * SNAP_SIZE_X) + DESKTOP_PAD_HORIZONTAL)
 116 #define SNAP_VERTICAL(func, y) ((func ((double)((y) - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y) * SNAP_SIZE_Y) + DESKTOP_PAD_VERTICAL)
 117 
 118 #define SNAP_NEAREST_HORIZONTAL(x) SNAP_HORIZONTAL (floor, x + .5)
 119 #define SNAP_NEAREST_VERTICAL(y) SNAP_VERTICAL (floor, y + .5)
 120 
 121 #define SNAP_CEIL_HORIZONTAL(x) SNAP_HORIZONTAL (ceil, x)
 122 #define SNAP_CEIL_VERTICAL(y) SNAP_VERTICAL (ceil, y)
 123 
 124 /* Copied from NautilusCanvasContainer */
 125 #define NAUTILUS_CANVAS_CONTAINER_SEARCH_DIALOG_TIMEOUT 5
 126 
 127 /* Copied from NautilusFile */
 128 #define UNDEFINED_TIME ((time_t) (-1))
 129 
 130 enum {
 131 	ACTION_ACTIVATE,
 132 	ACTION_MENU,
 133 	LAST_ACTION
 134 };
 135 
 136 typedef struct {
 137 	GList *selection;
 138 	char *action_descriptions[LAST_ACTION];
 139 } NautilusCanvasContainerAccessiblePrivate;
 140 
 141 static AtkObject *   get_accessible                                 (GtkWidget *widget);
 142 
 143 static void          preview_selected_items                         (NautilusCanvasContainer *container);
 144 static void          activate_selected_items                        (NautilusCanvasContainer *container);
 145 static void          activate_selected_items_alternate              (NautilusCanvasContainer *container,
 146 								     NautilusCanvasIcon          *icon);
 147 static void          compute_stretch                                (StretchState          *start,
 148 								     StretchState          *current);
 149 static NautilusCanvasIcon *get_first_selected_icon                        (NautilusCanvasContainer *container);
 150 static NautilusCanvasIcon *get_nth_selected_icon                          (NautilusCanvasContainer *container,
 151 									 int                    index);
 152 static gboolean      has_multiple_selection                         (NautilusCanvasContainer *container);
 153 static gboolean      all_selected                                   (NautilusCanvasContainer *container);
 154 static gboolean      has_selection                                  (NautilusCanvasContainer *container);
 155 static void          icon_destroy                                   (NautilusCanvasContainer *container,
 156 								       NautilusCanvasIcon          *icon);
 157 static void          end_renaming_mode                              (NautilusCanvasContainer *container,
 158 								     gboolean               commit);
 159 static NautilusCanvasIcon *get_icon_being_renamed                         (NautilusCanvasContainer *container);
 160 static void          finish_adding_new_icons                        (NautilusCanvasContainer *container);
 161 static inline void   icon_get_bounding_box                          (NautilusCanvasIcon          *icon,
 162 								       int                   *x1_return,
 163 								       int                   *y1_return,
 164 								       int                   *x2_return,
 165 								       int                   *y2_return,
 166 								       NautilusCanvasItemBoundsUsage usage);
 167 static gboolean      is_renaming                                    (NautilusCanvasContainer *container);
 168 static gboolean      is_renaming_pending                            (NautilusCanvasContainer *container);
 169 static void          process_pending_icon_to_rename                 (NautilusCanvasContainer *container);
 170 static void          nautilus_canvas_container_stop_monitor_top_left  (NautilusCanvasContainer *container,
 171 								       NautilusCanvasIconData      *data,
 172 								       gconstpointer          client);
 173 static void          nautilus_canvas_container_start_monitor_top_left (NautilusCanvasContainer *container,
 174 								       NautilusCanvasIconData      *data,
 175 								       gconstpointer          client,
 176 								       gboolean               large_text);
 177 static void          handle_hadjustment_changed                     (GtkAdjustment         *adjustment,
 178 								     NautilusCanvasContainer *container);
 179 static void          handle_vadjustment_changed                     (GtkAdjustment         *adjustment,
 180 								     NautilusCanvasContainer *container);
 181 static GList *       nautilus_canvas_container_get_selected_icons (NautilusCanvasContainer *container);
 182 static void          nautilus_canvas_container_update_visible_icons   (NautilusCanvasContainer *container);
 183 static void          reveal_icon                                    (NautilusCanvasContainer *container,
 184 								       NautilusCanvasIcon *icon);
 185 
 186 static void	     nautilus_canvas_container_set_rtl_positions (NautilusCanvasContainer *container);
 187 static double	     get_mirror_x_position                     (NautilusCanvasContainer *container,
 188 								NautilusCanvasIcon *icon,
 189 								double x);
 190 static void         text_ellipsis_limit_changed_container_callback  (gpointer callback_data);
 191 
 192 static int compare_icons_horizontal (NautilusCanvasContainer *container,
 193 				       NautilusCanvasIcon *icon_a,
 194 				       NautilusCanvasIcon *icon_b);
 195 
 196 static int compare_icons_vertical (NautilusCanvasContainer *container,
 197 				     NautilusCanvasIcon *icon_a,
 198 				     NautilusCanvasIcon *icon_b);
 199 
 200 static void store_layout_timestamps_now (NautilusCanvasContainer *container);
 201 
 202 static const char *nautilus_canvas_container_accessible_action_names[] = {
 203 	"activate",
 204 	"menu",
 205 	NULL
 206 };
 207 
 208 static const char *nautilus_canvas_container_accessible_action_descriptions[] = {
 209 	"Activate selected items",
 210 	"Popup context menu",
 211 	NULL
 212 };
 213 
 214 G_DEFINE_TYPE (NautilusCanvasContainer, nautilus_canvas_container, EEL_TYPE_CANVAS);
 215 
 216 /* The NautilusCanvasContainer signals.  */
 217 enum {
 218 	ACTIVATE,
 219 	ACTIVATE_ALTERNATE,
 220 	ACTIVATE_PREVIEWER,
 221 	BAND_SELECT_STARTED,
 222 	BAND_SELECT_ENDED,
 223 	BUTTON_PRESS,
 224 	CAN_ACCEPT_ITEM,
 225 	CONTEXT_CLICK_BACKGROUND,
 226 	CONTEXT_CLICK_SELECTION,
 227 	MIDDLE_CLICK,
 228 	GET_CONTAINER_URI,
 229 	GET_ICON_URI,
 230 	GET_ICON_DROP_TARGET_URI,
 231 	GET_STORED_ICON_POSITION,
 232 	ICON_POSITION_CHANGED,
 233 	GET_STORED_LAYOUT_TIMESTAMP,
 234 	STORE_LAYOUT_TIMESTAMP,
 235 	ICON_RENAME_STARTED,
 236 	ICON_RENAME_ENDED,
 237 	ICON_STRETCH_STARTED,
 238 	ICON_STRETCH_ENDED,
 239 	LAYOUT_CHANGED,
 240 	MOVE_COPY_ITEMS,
 241 	HANDLE_NETSCAPE_URL,
 242 	HANDLE_URI_LIST,
 243 	HANDLE_TEXT,
 244 	HANDLE_RAW,
 245 	SELECTION_CHANGED,
 246 	ICON_ADDED,
 247 	ICON_REMOVED,
 248 	CLEARED,
 249 	LAST_SIGNAL
 250 };
 251 
 252 typedef struct {
 253 	int **icon_grid;
 254 	int *grid_memory;
 255 	int num_rows;
 256 	int num_columns;
 257 	gboolean tight;
 258 } PlacementGrid;
 259 
 260 static guint signals[LAST_SIGNAL];
 261 
 262 /* Functions dealing with NautilusIcons.  */
 263 
 264 static void
 265 icon_free (NautilusCanvasIcon *icon)
 266 {
 267 	/* Destroy this icon item; the parent will unref it. */
 268 	eel_canvas_item_destroy (EEL_CANVAS_ITEM (icon->item));
 269 	g_free (icon);
 270 }
 271 
 272 static gboolean
 273 icon_is_positioned (const NautilusCanvasIcon *icon)
 274 {
 275 	return icon->x != ICON_UNPOSITIONED_VALUE && icon->y != ICON_UNPOSITIONED_VALUE;
 276 }
 277 
 278 
 279 /* x, y are the top-left coordinates of the icon. */
 280 static void
 281 icon_set_position (NautilusCanvasIcon *icon,
 282 		     double x, double y)
 283 {	
 284 	NautilusCanvasContainer *container;
 285 	double pixels_per_unit;	
 286 	int container_left, container_top, container_right, container_bottom;
 287 	int x1, x2, y1, y2;
 288 	int container_x, container_y, container_width, container_height;
 289 	EelDRect icon_bounds;
 290 	int item_width, item_height;
 291 	int height_above, width_left;
 292 	int min_x, max_x, min_y, max_y;
 293 
 294 	if (icon->x == x && icon->y == y) {
 295 		return;
 296 	}
 297 
 298 	container = NAUTILUS_CANVAS_CONTAINER (EEL_CANVAS_ITEM (icon->item)->canvas);
 299 
 300 	if (icon == get_icon_being_renamed (container)) {
 301 		end_renaming_mode (container, TRUE);
 302 	}
 303 
 304 	if (nautilus_canvas_container_get_is_fixed_size (container)) {
 305 		/*  FIXME: This should be:
 306 		    
 307 		    container_x = GTK_WIDGET (container)->allocation.x;
 308 		    container_y = GTK_WIDGET (container)->allocation.y;
 309 		    container_width = GTK_WIDGET (container)->allocation.width;
 310 		    container_height = GTK_WIDGET (container)->allocation.height;
 311 
 312 		    But for some reason the widget allocation is sometimes not done
 313 		    at startup, and the allocation is then only 45x60. which is
 314 		    really bad.
 315 
 316 		    For now, we have a cheesy workaround:
 317 		*/
 318 		container_x = 0;
 319 		container_y = 0;
 320 		container_width = gdk_screen_width () - container_x
 321 			- container->details->left_margin
 322 			- container->details->right_margin;
 323 		container_height = gdk_screen_height () - container_y
 324 			- container->details->top_margin
 325 			- container->details->bottom_margin;
 326 		pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit;
 327 		/* Clip the position of the icon within our desktop bounds */
 328 		container_left = container_x / pixels_per_unit;
 329 		container_top =  container_y / pixels_per_unit;
 330 		container_right = container_left + container_width / pixels_per_unit;
 331 		container_bottom = container_top + container_height / pixels_per_unit;
 332 
 333 		icon_get_bounding_box (icon, &x1, &y1, &x2, &y2,
 334 				       BOUNDS_USAGE_FOR_ENTIRE_ITEM);
 335 		item_width = x2 - x1;
 336 		item_height = y2 - y1;
 337 
 338 		icon_bounds = nautilus_canvas_item_get_icon_rectangle (icon->item);
 339 
 340 		/* determine icon rectangle relative to item rectangle */
 341 		height_above = icon_bounds.y0 - y1;
 342 		width_left = icon_bounds.x0 - x1;
 343 
 344 		min_x = container_left + DESKTOP_PAD_HORIZONTAL + width_left;
 345 		max_x = container_right - DESKTOP_PAD_HORIZONTAL - item_width + width_left;
 346 		x = CLAMP (x, min_x, max_x);
 347 
 348 		min_y = container_top + height_above + DESKTOP_PAD_VERTICAL;
 349 		max_y = container_bottom - DESKTOP_PAD_VERTICAL - item_height + height_above;
 350 		y = CLAMP (y, min_y, max_y);
 351 	}
 352 
 353 	if (icon->x == ICON_UNPOSITIONED_VALUE) {
 354 		icon->x = 0;
 355 	}
 356 	if (icon->y == ICON_UNPOSITIONED_VALUE) {
 357 		icon->y = 0;
 358 	}
 359 	
 360 	eel_canvas_item_move (EEL_CANVAS_ITEM (icon->item),
 361 			      x - icon->x,
 362 			      y - icon->y);
 363 
 364 	icon->x = x;
 365 	icon->y = y;
 366 }
 367 
 368 static void
 369 icon_get_size (NautilusCanvasContainer *container,
 370 		 NautilusCanvasIcon *icon,
 371 		 guint *size)
 372 {
 373 	if (size != NULL) {
 374 		*size = MAX (nautilus_get_icon_size_for_zoom_level (container->details->zoom_level)
 375 			     * icon->scale, NAUTILUS_ICON_SIZE_SMALLEST);
 376 	}
 377 }
 378 
 379 /* The icon_set_size function is used by the stretching user
 380  * interface, which currently stretches in a way that keeps the aspect
 381  * ratio. Later we might have a stretching interface that stretches Y
 382  * separate from X and we will change this around.
 383  */
 384 static void
 385 icon_set_size (NautilusCanvasContainer *container,
 386 		 NautilusCanvasIcon *icon,
 387 		 guint icon_size,
 388 		 gboolean snap,
 389 		 gboolean update_position)
 390 {
 391 	guint old_size;
 392 	double scale;
 393 
 394 	icon_get_size (container, icon, &old_size);
 395 	if (icon_size == old_size) {
 396 		return;
 397 	}
 398 
 399 	scale = (double) icon_size /
 400 		nautilus_get_icon_size_for_zoom_level
 401 		(container->details->zoom_level);
 402 	nautilus_canvas_container_move_icon (container, icon,
 403 					       icon->x, icon->y,
 404 					       scale, FALSE,
 405 					       snap, update_position);
 406 }
 407 
 408 static void
 409 icon_raise (NautilusCanvasIcon *icon)
 410 {
 411 	EelCanvasItem *item, *band;
 412 	
 413 	item = EEL_CANVAS_ITEM (icon->item);
 414 	band = NAUTILUS_CANVAS_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle;
 415 	
 416 	eel_canvas_item_send_behind (item, band);
 417 }
 418 
 419 static void
 420 emit_stretch_started (NautilusCanvasContainer *container, NautilusCanvasIcon *icon)
 421 {
 422 	g_signal_emit (container,
 423 		       signals[ICON_STRETCH_STARTED], 0,
 424 		       icon->data);
 425 }
 426 
 427 static void
 428 emit_stretch_ended (NautilusCanvasContainer *container, NautilusCanvasIcon *icon)
 429 {
 430 	g_signal_emit (container,
 431 		       signals[ICON_STRETCH_ENDED], 0,
 432 		       icon->data);
 433 }
 434 
 435 static void
 436 icon_toggle_selected (NautilusCanvasContainer *container,
 437 		      NautilusCanvasIcon *icon)
 438 {		
 439 	end_renaming_mode (container, TRUE);
 440 
 441 	icon->is_selected = !icon->is_selected;
 442 	eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item),
 443 			     "highlighted_for_selection", (gboolean) icon->is_selected,
 444 			     NULL);
 445 
 446 	/* If the icon is deselected, then get rid of the stretch handles.
 447 	 * No harm in doing the same if the item is newly selected.
 448 	 */
 449 	if (icon == container->details->stretch_icon) {
 450 		container->details->stretch_icon = NULL;
 451 		nautilus_canvas_item_set_show_stretch_handles (icon->item, FALSE);
 452 		/* snap the icon if necessary */
 453 		if (container->details->keep_aligned) {
 454 			nautilus_canvas_container_move_icon (container,
 455 							       icon,
 456 							       icon->x, icon->y,
 457 							       icon->scale,
 458 							       FALSE, TRUE, TRUE);
 459 		}
 460 		
 461 		emit_stretch_ended (container, icon);
 462 	}
 463 
 464 	/* Raise each newly-selected icon to the front as it is selected. */
 465 	if (icon->is_selected) {
 466 		icon_raise (icon);
 467 	}
 468 }
 469 
 470 /* Select an icon. Return TRUE if selection has changed. */
 471 static gboolean
 472 icon_set_selected (NautilusCanvasContainer *container,
 473 		     NautilusCanvasIcon *icon,
 474 		     gboolean select)
 475 {
 476 	g_assert (select == FALSE || select == TRUE);
 477 	g_assert (icon->is_selected == FALSE || icon->is_selected == TRUE);
 478 
 479 	if (select == icon->is_selected) {
 480 		return FALSE;
 481 	}
 482 
 483 	icon_toggle_selected (container, icon);
 484 	g_assert (select == icon->is_selected);
 485 	return TRUE;
 486 }
 487 
 488 static inline void
 489 icon_get_bounding_box (NautilusCanvasIcon *icon,
 490 		       int *x1_return, int *y1_return,
 491 		       int *x2_return, int *y2_return,
 492 		       NautilusCanvasItemBoundsUsage usage)
 493 {
 494 	double x1, y1, x2, y2;
 495 
 496 	if (usage == BOUNDS_USAGE_FOR_DISPLAY) {
 497 		eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item),
 498 					    &x1, &y1, &x2, &y2);
 499 	} else if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
 500 		nautilus_canvas_item_get_bounds_for_layout (icon->item,
 501 								   &x1, &y1, &x2, &y2);
 502 	} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
 503 		nautilus_canvas_item_get_bounds_for_entire_item (icon->item,
 504 									&x1, &y1, &x2, &y2);
 505 	} else {
 506 		g_assert_not_reached ();
 507 	}
 508 
 509 	if (x1_return != NULL) {
 510 		*x1_return = x1;
 511 	}
 512 
 513 	if (y1_return != NULL) {
 514 		*y1_return = y1;
 515 	}
 516 
 517 	if (x2_return != NULL) {
 518 		*x2_return = x2;
 519 	}
 520 
 521 	if (y2_return != NULL) {
 522 		*y2_return = y2;
 523 	}
 524 }
 525 
 526 /* Utility functions for NautilusCanvasContainer.  */
 527 
 528 gboolean
 529 nautilus_canvas_container_scroll (NautilusCanvasContainer *container,
 530 				  int delta_x, int delta_y)
 531 {
 532 	GtkAdjustment *hadj, *vadj;
 533 	int old_h_value, old_v_value;
 534 
 535 	hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
 536 	vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
 537 
 538 	/* Store the old ajustment values so we can tell if we
 539 	 * ended up actually scrolling. We may not have in a case
 540 	 * where the resulting value got pinned to the adjustment
 541 	 * min or max.
 542 	 */
 543 	old_h_value = gtk_adjustment_get_value (hadj);
 544 	old_v_value = gtk_adjustment_get_value (vadj);
 545 	
 546 	gtk_adjustment_set_value (hadj, gtk_adjustment_get_value (hadj) + delta_x);
 547 	gtk_adjustment_set_value (vadj, gtk_adjustment_get_value (vadj) + delta_y);
 548 
 549 	/* return TRUE if we did scroll */
 550 	return gtk_adjustment_get_value (hadj) != old_h_value || gtk_adjustment_get_value (vadj) != old_v_value;
 551 }
 552 
 553 static void
 554 pending_icon_to_reveal_destroy_callback (NautilusCanvasItem *item,
 555 					   NautilusCanvasContainer *container)
 556 {
 557 	g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
 558 	g_assert (container->details->pending_icon_to_reveal != NULL);
 559 	g_assert (container->details->pending_icon_to_reveal->item == item);
 560 
 561 	container->details->pending_icon_to_reveal = NULL;
 562 }
 563 
 564 static NautilusCanvasIcon *
 565 get_pending_icon_to_reveal (NautilusCanvasContainer *container)
 566 {
 567 	return container->details->pending_icon_to_reveal;
 568 }
 569 
 570 static void
 571 set_pending_icon_to_reveal (NautilusCanvasContainer *container, NautilusCanvasIcon *icon)
 572 {
 573 	NautilusCanvasIcon *old_icon;
 574 	
 575 	old_icon = container->details->pending_icon_to_reveal;
 576 	
 577 	if (icon == old_icon) {
 578 		return;
 579 	}
 580 	
 581 	if (old_icon != NULL) {
 582 		g_signal_handlers_disconnect_by_func
 583 			(old_icon->item,
 584 			 G_CALLBACK (pending_icon_to_reveal_destroy_callback),
 585 			 container);
 586 	}
 587 	
 588 	if (icon != NULL) {
 589 		g_signal_connect (icon->item, "destroy",
 590 				  G_CALLBACK (pending_icon_to_reveal_destroy_callback),
 591 				  container);
 592 	}
 593 	
 594 	container->details->pending_icon_to_reveal = icon;
 595 }
 596 
 597 static void
 598 item_get_canvas_bounds (EelCanvasItem *item,
 599 			EelIRect *bounds,
 600 			gboolean safety_pad)
 601 {
 602 	EelDRect world_rect;
 603 	
 604 	eel_canvas_item_get_bounds (item,
 605 				    &world_rect.x0,
 606 				    &world_rect.y0,
 607 				    &world_rect.x1,
 608 				    &world_rect.y1);
 609 	eel_canvas_item_i2w (item->parent,
 610 			     &world_rect.x0,
 611 			     &world_rect.y0);
 612 	eel_canvas_item_i2w (item->parent,
 613 			     &world_rect.x1,
 614 			     &world_rect.y1);
 615 	if (safety_pad) {
 616 		world_rect.x0 -= ICON_PAD_LEFT + ICON_PAD_RIGHT;
 617 		world_rect.x1 += ICON_PAD_LEFT + ICON_PAD_RIGHT;
 618 
 619 		world_rect.y0 -= ICON_PAD_TOP + ICON_PAD_BOTTOM;
 620 		world_rect.y1 += ICON_PAD_TOP + ICON_PAD_BOTTOM;
 621 	}
 622 
 623 	eel_canvas_w2c (item->canvas,
 624 			world_rect.x0,
 625 			world_rect.y0,
 626 			&bounds->x0,
 627 			&bounds->y0);
 628 	eel_canvas_w2c (item->canvas,
 629 			world_rect.x1,
 630 			world_rect.y1,
 631 			&bounds->x1,
 632 			&bounds->y1);
 633 }
 634 
 635 static void
 636 icon_get_row_and_column_bounds (NautilusCanvasContainer *container,
 637 				NautilusCanvasIcon *icon,
 638 				EelIRect *bounds,
 639 				gboolean safety_pad)
 640 {
 641 	GList *p;
 642 	NautilusCanvasIcon *one_icon;
 643 	EelIRect one_bounds;
 644 
 645 	item_get_canvas_bounds (EEL_CANVAS_ITEM (icon->item), bounds, safety_pad);
 646 
 647 	for (p = container->details->icons; p != NULL; p = p->next) {
 648 		one_icon = p->data;
 649 
 650 		if (icon == one_icon) {
 651 			continue;
 652 		}
 653 
 654 		if (compare_icons_horizontal (container, icon, one_icon) == 0) {
 655 			item_get_canvas_bounds (EEL_CANVAS_ITEM (one_icon->item), &one_bounds, safety_pad);
 656 			bounds->x0 = MIN (bounds->x0, one_bounds.x0);
 657 			bounds->x1 = MAX (bounds->x1, one_bounds.x1);
 658 		}
 659 
 660 		if (compare_icons_vertical (container, icon, one_icon) == 0) {
 661 			item_get_canvas_bounds (EEL_CANVAS_ITEM (one_icon->item), &one_bounds, safety_pad);
 662 			bounds->y0 = MIN (bounds->y0, one_bounds.y0);
 663 			bounds->y1 = MAX (bounds->y1, one_bounds.y1);
 664 		}
 665 	}
 666 
 667 
 668 }
 669 
 670 static void
 671 reveal_icon (NautilusCanvasContainer *container,
 672 	     NautilusCanvasIcon *icon)
 673 {
 674 	GtkAllocation allocation;
 675 	GtkAdjustment *hadj, *vadj;
 676 	EelIRect bounds;
 677 
 678 	if (!icon_is_positioned (icon)) {
 679 		set_pending_icon_to_reveal (container, icon);
 680 		return;
 681 	}
 682 	
 683 	set_pending_icon_to_reveal (container, NULL);
 684 
 685 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
 686 
 687 	hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
 688 	vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
 689 
 690 	if (nautilus_canvas_container_is_auto_layout (container)) {
 691 		/* ensure that we reveal the entire row/column */
 692 		icon_get_row_and_column_bounds (container, icon, &bounds, TRUE);
 693 	} else {
 694 		item_get_canvas_bounds (EEL_CANVAS_ITEM (icon->item), &bounds, TRUE);
 695 	}
 696 	if (bounds.y0 < gtk_adjustment_get_value (vadj)) {
 697 		gtk_adjustment_set_value (vadj, bounds.y0);
 698 	} else if (bounds.y1 > gtk_adjustment_get_value (vadj) + allocation.height) {
 699 		gtk_adjustment_set_value
 700 			(vadj, bounds.y1 - allocation.height);
 701 	}
 702 
 703 	if (bounds.x0 < gtk_adjustment_get_value (hadj)) {
 704 		gtk_adjustment_set_value (hadj, bounds.x0);
 705 	} else if (bounds.x1 > gtk_adjustment_get_value (hadj) + allocation.width) {
 706 		gtk_adjustment_set_value
 707 			(hadj, bounds.x1 - allocation.width);
 708 	}
 709 }
 710 
 711 static void
 712 process_pending_icon_to_reveal (NautilusCanvasContainer *container)
 713 {
 714 	NautilusCanvasIcon *pending_icon_to_reveal;
 715 	
 716 	pending_icon_to_reveal = get_pending_icon_to_reveal (container);
 717 	
 718 	if (pending_icon_to_reveal != NULL) {
 719 		reveal_icon (container, pending_icon_to_reveal);
 720 	}
 721 }
 722 
 723 static gboolean
 724 keyboard_icon_reveal_timeout_callback (gpointer data)
 725 {
 726 	NautilusCanvasContainer *container;
 727 	NautilusCanvasIcon *icon;
 728 
 729 	container = NAUTILUS_CANVAS_CONTAINER (data);
 730 	icon = container->details->keyboard_icon_to_reveal;
 731 
 732 	g_assert (icon != NULL);
 733 
 734 	/* Only reveal the icon if it's still the keyboard focus or if
 735 	 * it's still selected. Someone originally thought we should
 736 	 * cancel this reveal if the user manages to sneak a direct
 737 	 * scroll in before the timeout fires, but we later realized
 738 	 * this wouldn't actually be an improvement 
 739 	 * (see bugzilla.gnome.org 40612).
 740 	 */
 741 	if (icon == container->details->keyboard_focus
 742 	    || icon->is_selected) {
 743 		reveal_icon (container, icon);
 744 	}
 745 	container->details->keyboard_icon_reveal_timer_id = 0;
 746 
 747 	return FALSE;
 748 }
 749 
 750 static void
 751 unschedule_keyboard_icon_reveal (NautilusCanvasContainer *container)
 752 {
 753 	NautilusCanvasContainerDetails *details;
 754 
 755 	details = container->details;
 756 
 757 	if (details->keyboard_icon_reveal_timer_id != 0) {
 758 		g_source_remove (details->keyboard_icon_reveal_timer_id);
 759 	}
 760 }
 761 
 762 static void
 763 schedule_keyboard_icon_reveal (NautilusCanvasContainer *container,
 764 				 NautilusCanvasIcon *icon)
 765 {
 766 	NautilusCanvasContainerDetails *details;
 767 
 768 	details = container->details;
 769 
 770 	unschedule_keyboard_icon_reveal (container);
 771 
 772 	details->keyboard_icon_to_reveal = icon;
 773 	details->keyboard_icon_reveal_timer_id
 774 		= g_timeout_add (KEYBOARD_ICON_REVEAL_TIMEOUT,
 775 				 keyboard_icon_reveal_timeout_callback,
 776 				 container);
 777 }
 778 
 779 static void
 780 clear_keyboard_focus (NautilusCanvasContainer *container)
 781 {
 782         if (container->details->keyboard_focus != NULL) {
 783 		eel_canvas_item_set (EEL_CANVAS_ITEM (container->details->keyboard_focus->item),
 784 				     "highlighted_as_keyboard_focus", 0,
 785 				     NULL);
 786 	}
 787 	
 788 	container->details->keyboard_focus = NULL;
 789 }
 790 
 791 static void inline
 792 emit_atk_focus_tracker_notify (NautilusCanvasIcon *icon)
 793 {
 794 	AtkObject *atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item));
 795 	atk_focus_tracker_notify (atk_object);
 796 }
 797 
 798 /* Set @icon as the icon currently selected for keyboard operations. */
 799 static void
 800 set_keyboard_focus (NautilusCanvasContainer *container,
 801 		    NautilusCanvasIcon *icon)
 802 {
 803 	g_assert (icon != NULL);
 804 
 805 	if (icon == container->details->keyboard_focus) {
 806 		return;
 807 	}
 808 
 809 	clear_keyboard_focus (container);
 810 
 811 	container->details->keyboard_focus = icon;
 812 
 813 	eel_canvas_item_set (EEL_CANVAS_ITEM (container->details->keyboard_focus->item),
 814 			     "highlighted_as_keyboard_focus", 1,
 815 			     NULL);
 816 
 817 	emit_atk_focus_tracker_notify (icon);
 818 }
 819 
 820 static void
 821 set_keyboard_rubberband_start (NautilusCanvasContainer *container,
 822 			       NautilusCanvasIcon *icon)
 823 {
 824 	container->details->keyboard_rubberband_start = icon;
 825 }
 826 
 827 static void
 828 clear_keyboard_rubberband_start (NautilusCanvasContainer *container)
 829 {
 830 	container->details->keyboard_rubberband_start = NULL;
 831 }
 832 
 833 /* carbon-copy of eel_canvas_group_bounds(), but
 834  * for NautilusCanvasContainerItems it returns the
 835  * bounds for the “entire item”.
 836  */
 837 static void
 838 get_icon_bounds_for_canvas_bounds (EelCanvasGroup *group,
 839 				     double *x1, double *y1,
 840 				     double *x2, double *y2,
 841 				     NautilusCanvasItemBoundsUsage usage)
 842 {
 843 	EelCanvasItem *child;
 844 	GList *list;
 845 	double tx1, ty1, tx2, ty2;
 846 	double minx, miny, maxx, maxy;
 847 	int set;
 848 
 849 	/* Get the bounds of the first visible item */
 850 
 851 	child = NULL; /* Unnecessary but eliminates a warning. */
 852 
 853 	set = FALSE;
 854 
 855 	for (list = group->item_list; list; list = list->next) {
 856 		child = list->data;
 857 
 858 		if (!NAUTILUS_IS_CANVAS_ITEM (child)) {
 859 			continue;
 860 		}
 861 
 862 		if (child->flags & EEL_CANVAS_ITEM_VISIBLE) {
 863 			set = TRUE;
 864 			if (!NAUTILUS_IS_CANVAS_ITEM (child) ||
 865 			    usage == BOUNDS_USAGE_FOR_DISPLAY) {
 866 				eel_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy);
 867 			} else if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
 868 				nautilus_canvas_item_get_bounds_for_layout (NAUTILUS_CANVAS_ITEM (child),
 869 										   &minx, &miny, &maxx, &maxy);
 870 			} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
 871 				nautilus_canvas_item_get_bounds_for_entire_item (NAUTILUS_CANVAS_ITEM (child),
 872 											&minx, &miny, &maxx, &maxy);
 873 			} else {
 874 				g_assert_not_reached ();
 875 			}
 876 			break;
 877 		}
 878 	}
 879 
 880 	/* If there were no visible items, return an empty bounding box */
 881 
 882 	if (!set) {
 883 		*x1 = *y1 = *x2 = *y2 = 0.0;
 884 		return;
 885 	}
 886 
 887 	/* Now we can grow the bounds using the rest of the items */
 888 
 889 	list = list->next;
 890 
 891 	for (; list; list = list->next) {
 892 		child = list->data;
 893 
 894 		if (!NAUTILUS_IS_CANVAS_ITEM (child)) {
 895 			continue;
 896 		}
 897 
 898 		if (!(child->flags & EEL_CANVAS_ITEM_VISIBLE))
 899 			continue;
 900 
 901 		if (!NAUTILUS_IS_CANVAS_ITEM (child) ||
 902 		    usage == BOUNDS_USAGE_FOR_DISPLAY) {
 903 			eel_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2);
 904 		} else if (usage == BOUNDS_USAGE_FOR_LAYOUT) {
 905 			nautilus_canvas_item_get_bounds_for_layout (NAUTILUS_CANVAS_ITEM (child),
 906 									   &tx1, &ty1, &tx2, &ty2);
 907 		} else if (usage == BOUNDS_USAGE_FOR_ENTIRE_ITEM) {
 908 			nautilus_canvas_item_get_bounds_for_entire_item (NAUTILUS_CANVAS_ITEM (child),
 909 										&tx1, &ty1, &tx2, &ty2);
 910 		} else {
 911 			g_assert_not_reached ();
 912 		}
 913 
 914 		if (tx1 < minx)
 915 			minx = tx1;
 916 
 917 		if (ty1 < miny)
 918 			miny = ty1;
 919 
 920 		if (tx2 > maxx)
 921 			maxx = tx2;
 922 
 923 		if (ty2 > maxy)
 924 			maxy = ty2;
 925 	}
 926 
 927 	/* Make the bounds be relative to our parent's coordinate system */
 928 
 929 	if (EEL_CANVAS_ITEM (group)->parent) {
 930 		minx += group->xpos;
 931 		miny += group->ypos;
 932 		maxx += group->xpos;
 933 		maxy += group->ypos;
 934 	}
 935 	
 936 	if (x1 != NULL) {
 937 		*x1 = minx;
 938 	}
 939 
 940 	if (y1 != NULL) {
 941 		*y1 = miny;
 942 	}
 943 
 944 	if (x2 != NULL) {
 945 		*x2 = maxx;
 946 	}
 947 
 948 	if (y2 != NULL) {
 949 		*y2 = maxy;
 950 	}
 951 }
 952 
 953 static void
 954 get_all_icon_bounds (NautilusCanvasContainer *container,
 955 		     double *x1, double *y1,
 956 		     double *x2, double *y2,
 957 		     NautilusCanvasItemBoundsUsage usage)
 958 {
 959 	/* FIXME bugzilla.gnome.org 42477: Do we have to do something about the rubberband
 960 	 * here? Any other non-icon items?
 961 	 */
 962 	get_icon_bounds_for_canvas_bounds (EEL_CANVAS_GROUP (EEL_CANVAS (container)->root),
 963 					     x1, y1, x2, y2, usage);
 964 }
 965 
 966 /* Don't preserve visible white space the next time the scroll region
 967  * is recomputed when the container is not empty. */
 968 void
 969 nautilus_canvas_container_reset_scroll_region (NautilusCanvasContainer *container)
 970 {
 971 	container->details->reset_scroll_region_trigger = TRUE;
 972 }
 973 
 974 /* Set a new scroll region without eliminating any of the currently-visible area. */
 975 static void
 976 canvas_set_scroll_region_include_visible_area (EelCanvas *canvas,
 977 					       double x1, double y1,
 978 					       double x2, double y2)
 979 {
 980 	double old_x1, old_y1, old_x2, old_y2;
 981 	double old_scroll_x, old_scroll_y;
 982 	double height, width;
 983 	GtkAllocation allocation;
 984 	
 985 	eel_canvas_get_scroll_region (canvas, &old_x1, &old_y1, &old_x2, &old_y2);
 986 	gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation);
 987 
 988 	width = (allocation.width) / canvas->pixels_per_unit;
 989 	height = (allocation.height) / canvas->pixels_per_unit;
 990 
 991 	old_scroll_x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)));
 992 	old_scroll_y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)));
 993 
 994 	x1 = MIN (x1, old_x1 + old_scroll_x);
 995 	y1 = MIN (y1, old_y1 + old_scroll_y);
 996 	x2 = MAX (x2, old_x1 + old_scroll_x + width);
 997 	y2 = MAX (y2, old_y1 + old_scroll_y + height);
 998 
 999 	eel_canvas_set_scroll_region
1000 		(canvas, x1, y1, x2, y2);
1001 }
1002 
1003 void
1004 nautilus_canvas_container_update_scroll_region (NautilusCanvasContainer *container)
1005 {
1006 	double x1, y1, x2, y2;
1007 	double pixels_per_unit;
1008 	GtkAdjustment *hadj, *vadj;
1009 	float step_increment;
1010 	gboolean reset_scroll_region;
1011 	GtkAllocation allocation;
1012 
1013 	pixels_per_unit = EEL_CANVAS (container)->pixels_per_unit;
1014 
1015 	if (nautilus_canvas_container_get_is_fixed_size (container)) {
1016 		/* Set the scroll region to the size of the container allocation */
1017 		gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1018 		eel_canvas_set_scroll_region
1019 			(EEL_CANVAS (container),
1020 			 (double) - container->details->left_margin / pixels_per_unit,
1021 			 (double) - container->details->top_margin / pixels_per_unit,
1022 			 ((double) (allocation.width - 1)
1023 			  - container->details->left_margin
1024 			  - container->details->right_margin)
1025 			 / pixels_per_unit,
1026 			 ((double) (allocation.height - 1)
1027 			  - container->details->top_margin
1028 			  - container->details->bottom_margin)
1029 			 / pixels_per_unit);
1030 		return;
1031 	}
1032 
1033 	reset_scroll_region = container->details->reset_scroll_region_trigger
1034 		|| nautilus_canvas_container_is_empty (container)
1035 		|| nautilus_canvas_container_is_auto_layout (container);
1036 
1037 	/* The trigger is only cleared when container is non-empty, so
1038 	 * callers can reliably reset the scroll region when an item
1039 	 * is added even if extraneous relayouts are called when the
1040 	 * window is still empty.
1041 	 */
1042 	if (!nautilus_canvas_container_is_empty (container)) {
1043 		container->details->reset_scroll_region_trigger = FALSE;
1044 	}
1045 
1046 	get_all_icon_bounds (container, &x1, &y1, &x2, &y2, BOUNDS_USAGE_FOR_ENTIRE_ITEM);
1047 
1048 	/* Add border at the "end"of the layout (i.e. after the icons), to
1049 	 * ensure we get some space when scrolled to the end.
1050 	 * For horizontal layouts, we add a bottom border.
1051 	 * Vertical layout is used by the compact view so the end
1052 	 * depends on the RTL setting.
1053 	 */
1054 	if (nautilus_canvas_container_is_layout_vertical (container)) {
1055 		if (nautilus_canvas_container_is_layout_rtl (container)) {
1056 			x1 -= ICON_PAD_LEFT + CONTAINER_PAD_LEFT;
1057 		} else {
1058 			x2 += ICON_PAD_RIGHT + CONTAINER_PAD_RIGHT;
1059 		}
1060 	} else {
1061 		y2 += ICON_PAD_BOTTOM + CONTAINER_PAD_BOTTOM;
1062 	}
1063 
1064 	/* Auto-layout assumes a 0, 0 scroll origin and at least allocation->width.
1065 	 * Then we lay out to the right or to the left, so
1066 	 * x can be < 0 and > allocation */
1067 	if (nautilus_canvas_container_is_auto_layout (container)) {
1068 		gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1069 		x1 = MIN (x1, 0);
1070 		x2 = MAX (x2, allocation.width / pixels_per_unit);
1071 		y1 = 0;
1072 	} else {
1073 		/* Otherwise we add the padding that is at the start of the
1074 		   layout */
1075 		if (nautilus_canvas_container_is_layout_rtl (container)) {
1076 			x2 += ICON_PAD_RIGHT + CONTAINER_PAD_RIGHT;
1077 		} else {
1078 			x1 -= ICON_PAD_LEFT + CONTAINER_PAD_LEFT;
1079 		}
1080 		y1 -= ICON_PAD_TOP + CONTAINER_PAD_TOP;
1081 	}
1082 
1083 	x2 -= 1;
1084 	x2 = MAX(x1, x2);
1085 
1086 	y2 -= 1;
1087 	y2 = MAX(y1, y2);
1088 
1089 	if (reset_scroll_region) {
1090 		eel_canvas_set_scroll_region
1091 			(EEL_CANVAS (container),
1092 			 x1, y1, x2, y2);
1093 	} else {
1094 		canvas_set_scroll_region_include_visible_area
1095 			(EEL_CANVAS (container),
1096 			 x1, y1, x2, y2);
1097 	}
1098 
1099 	hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
1100 	vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
1101 
1102 	/* Scroll by 1/4 icon each time you click. */
1103 	step_increment = nautilus_get_icon_size_for_zoom_level
1104 		(container->details->zoom_level) / 4;
1105 	if (gtk_adjustment_get_step_increment (hadj) != step_increment) {
1106 		gtk_adjustment_set_step_increment (hadj, step_increment);
1107 	}
1108 	if (gtk_adjustment_get_step_increment (vadj) != step_increment) {
1109 		gtk_adjustment_set_step_increment (vadj, step_increment);
1110 	}
1111 }
1112 
1113 static int
1114 compare_icons (gconstpointer a, gconstpointer b, gpointer canvas_container)
1115 {
1116 	NautilusCanvasContainerClass *klass;
1117 	const NautilusCanvasIcon *icon_a, *icon_b;
1118 
1119 	icon_a = a;
1120 	icon_b = b;
1121 	klass  = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (canvas_container);
1122 
1123 	return klass->compare_icons (canvas_container, icon_a->data, icon_b->data);
1124 }
1125 
1126 static void
1127 sort_icons (NautilusCanvasContainer *container,
1128 	      GList                **icons)
1129 {
1130 	NautilusCanvasContainerClass *klass;
1131 
1132 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
1133 	g_assert (klass->compare_icons != NULL);
1134 
1135 	*icons = g_list_sort_with_data (*icons, compare_icons, container);
1136 }
1137 
1138 static void
1139 resort (NautilusCanvasContainer *container)
1140 {
1141 	sort_icons (container, &container->details->icons);
1142 }
1143 
1144 #if 0
1145 static double
1146 get_grid_width (NautilusCanvasContainer *container)
1147 {
1148 	return STANDARD_ICON_GRID_WIDTH;
1149 }
1150 #endif
1151 typedef struct {
1152 	double width;
1153 	double height;
1154 	double x_offset;
1155 	double y_offset;
1156 } IconPositions;
1157 
1158 static void
1159 lay_down_one_line (NautilusCanvasContainer *container,
1160 		   GList *line_start,
1161 		   GList *line_end,
1162 		   double y,
1163 		   double max_height,
1164 		   GArray *positions,
1165 		   gboolean whole_text)
1166 {
1167 	GList *p;
1168 	NautilusCanvasIcon *icon;
1169 	double x, y_offset;
1170 	IconPositions *position;
1171 	int i;
1172 	gboolean is_rtl;
1173 
1174 	is_rtl = nautilus_canvas_container_is_layout_rtl (container);
1175 
1176 	/* Lay out the icons along the baseline. */
1177 	x = ICON_PAD_LEFT;
1178 	i = 0;
1179 	for (p = line_start; p != line_end; p = p->next) {
1180 		icon = p->data;
1181 
1182 		position = &g_array_index (positions, IconPositions, i++);
1183 		y_offset = position->y_offset;
1184 
1185 		icon_set_position
1186 			(icon,
1187 			 is_rtl ? get_mirror_x_position (container, icon, x + position->x_offset) : x + position->x_offset,
1188 			 y + y_offset);
1189 		nautilus_canvas_item_set_entire_text (icon->item, whole_text);
1190 
1191 		icon->saved_ltr_x = is_rtl ? get_mirror_x_position (container, icon, icon->x) : icon->x;
1192 
1193 		x += position->width;
1194 	}
1195 }
1196 
1197 static void
1198 lay_down_one_column (NautilusCanvasContainer *container,
1199 		     GList *line_start,
1200 		     GList *line_end,
1201 		     double x,
1202 		     double y_start,
1203 		     double y_iter,
1204 		     GArray *positions)
1205 {
1206 	GList *p;
1207 	NautilusCanvasIcon *icon;
1208 	double y;
1209 	IconPositions *position;
1210 	int i;
1211 	gboolean is_rtl;
1212 
1213         is_rtl = nautilus_canvas_container_is_layout_rtl (container);
1214 
1215 	/* Lay out the icons along the baseline. */
1216 	y = y_start;
1217 	i = 0;
1218 	for (p = line_start; p != line_end; p = p->next) {
1219 		icon = p->data;
1220 
1221 		position = &g_array_index (positions, IconPositions, i++);
1222 
1223 		icon_set_position
1224 			(icon,
1225 			 is_rtl ? get_mirror_x_position (container, icon, x + position->x_offset) : x + position->x_offset,
1226 			 y + position->y_offset);
1227 
1228 		icon->saved_ltr_x = is_rtl ? get_mirror_x_position (container, icon, icon->x) : icon->x;
1229 
1230 		y += y_iter;
1231 	}
1232 }
1233 
1234 static void
1235 lay_down_icons_horizontal (NautilusCanvasContainer *container,
1236 			     GList *icons,
1237 			     double start_y)
1238 {
1239 	GList *p, *line_start;
1240 	NautilusCanvasIcon *icon;
1241 	double canvas_width, y;
1242 	GArray *positions;
1243 	IconPositions *position;
1244 	EelDRect bounds;
1245 	EelDRect icon_bounds;
1246 	double max_height_above, max_height_below;
1247 	double height_above, height_below;
1248 	double line_width;
1249 	double grid_width;
1250 	int icon_width;
1251 	int i;
1252 	GtkAllocation allocation;
1253 
1254 	g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1255 
1256 	if (icons == NULL) {
1257 		return;
1258 	}
1259 
1260 	positions = g_array_new (FALSE, FALSE, sizeof (IconPositions));
1261 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1262 	
1263 	/* Lay out icons a line at a time. */
1264 	canvas_width = CANVAS_WIDTH(container, allocation);
1265 
1266 	grid_width = STANDARD_ICON_GRID_WIDTH;
1267 
1268 	line_width = 0;
1269 	line_start = icons;
1270 	y = start_y + CONTAINER_PAD_TOP;
1271 	i = 0;
1272 	
1273 	max_height_above = 0;
1274 	max_height_below = 0;
1275 	for (p = icons; p != NULL; p = p->next) {
1276 		icon = p->data;
1277 
1278 		/* Assume it's only one level hierarchy to avoid costly affine calculations */
1279 		nautilus_canvas_item_get_bounds_for_layout (icon->item,
1280 								   &bounds.x0, &bounds.y0,
1281 								   &bounds.x1, &bounds.y1);
1282 
1283 		icon_bounds = nautilus_canvas_item_get_icon_rectangle (icon->item);
1284 		icon_width = ceil ((bounds.x1 - bounds.x0)/grid_width) * grid_width;
1285 		
1286 		/* Calculate size above/below baseline */
1287 		height_above = icon_bounds.y1 - bounds.y0;
1288 		height_below = bounds.y1 - icon_bounds.y1;
1289 
1290 		/* If this icon doesn't fit, it's time to lay out the line that's queued up. */
1291 		if (line_start != p && line_width + icon_width >= canvas_width ) {
1292 			/* Advance to the baseline. */
1293 			y += ICON_PAD_TOP + max_height_above;
1294 
1295 			lay_down_one_line (container, line_start, p, y, max_height_above, positions, FALSE);
1296 
1297 			/* Advance to next line. */
1298 			y += max_height_below + ICON_PAD_BOTTOM;
1299 
1300 			line_width = 0;
1301 			line_start = p;
1302 			i = 0;
1303 			
1304 			max_height_above = height_above;
1305 			max_height_below = height_below;
1306 		} else {
1307 			if (height_above > max_height_above) {
1308 				max_height_above = height_above;
1309 			}
1310 			if (height_below > max_height_below) {
1311 				max_height_below = height_below;
1312 			}
1313 		}
1314 		
1315 		g_array_set_size (positions, i + 1);
1316 		position = &g_array_index (positions, IconPositions, i++);
1317 		position->width = icon_width;
1318 		position->height = icon_bounds.y1 - icon_bounds.y0;
1319 
1320 		position->x_offset = (icon_width - (icon_bounds.x1 - icon_bounds.x0)) / 2;
1321 		position->y_offset = icon_bounds.y0 - icon_bounds.y1;
1322 
1323 		/* Add this icon. */
1324 		line_width += icon_width;
1325 	}
1326 
1327 	/* Lay down that last line of icons. */
1328 	if (line_start != NULL) {
1329 		/* Advance to the baseline. */
1330 		y += ICON_PAD_TOP + max_height_above;
1331 
1332 		lay_down_one_line (container, line_start, NULL, y, max_height_above, positions, TRUE);
1333 	}
1334 
1335 	g_array_free (positions, TRUE);
1336 }
1337 
1338 static void
1339 get_max_icon_dimensions (GList *icon_start,
1340 			 GList *icon_end,
1341 			 double *max_icon_width,
1342 			 double *max_icon_height,
1343 			 double *max_text_width,
1344 			 double *max_text_height,
1345 			 double *max_bounds_height)
1346 {
1347 	NautilusCanvasIcon *icon;
1348 	EelDRect icon_bounds;
1349 	EelDRect text_bounds;
1350 	GList *p;
1351 	double y1, y2;
1352 
1353 	*max_icon_width = *max_text_width = 0.0;
1354 	*max_icon_height = *max_text_height = 0.0;
1355 	*max_bounds_height = 0.0;
1356 
1357 	/* Would it be worth caching these bounds for the next loop? */
1358 	for (p = icon_start; p != icon_end; p = p->next) {
1359 		icon = p->data;
1360 
1361 		icon_bounds = nautilus_canvas_item_get_icon_rectangle (icon->item);
1362 		*max_icon_width = MAX (*max_icon_width, ceil (icon_bounds.x1 - icon_bounds.x0));
1363 		*max_icon_height = MAX (*max_icon_height, ceil (icon_bounds.y1 - icon_bounds.y0));
1364 
1365 		text_bounds = nautilus_canvas_item_get_text_rectangle (icon->item, TRUE);
1366 		*max_text_width = MAX (*max_text_width, ceil (text_bounds.x1 - text_bounds.x0));
1367 		*max_text_height = MAX (*max_text_height, ceil (text_bounds.y1 - text_bounds.y0));
1368 
1369 		nautilus_canvas_item_get_bounds_for_layout (icon->item,
1370 								   NULL, &y1,
1371 								   NULL, &y2);
1372 		*max_bounds_height = MAX (*max_bounds_height, y2 - y1);
1373 	}
1374 }
1375 
1376 static void
1377 lay_down_icons_vertical (NautilusCanvasContainer *container,
1378 			   GList *icons,
1379 			   double start_y)
1380 {
1381 	GList *p, *line_start;
1382 	NautilusCanvasIcon *icon;
1383 	double x, canvas_height;
1384 	GArray *positions;
1385 	IconPositions *position;
1386 	EelDRect icon_bounds;
1387 	EelDRect text_bounds;
1388 	GtkAllocation allocation;
1389 
1390 	double line_height;
1391 
1392 	double max_height;
1393 	double max_height_with_borders;
1394 	double max_width;
1395 	double max_width_in_column;
1396 
1397 	double max_bounds_height;
1398 	double max_bounds_height_with_borders;
1399 
1400 	double max_text_width, max_icon_width;
1401 	double max_text_height, max_icon_height;
1402 	int height;
1403 	int i;
1404 
1405 	g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1406 
1407 	if (icons == NULL) {
1408 		return;
1409 	}
1410 
1411 	positions = g_array_new (FALSE, FALSE, sizeof (IconPositions));
1412 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1413 
1414 	/* Lay out icons a column at a time. */
1415 	canvas_height = CANVAS_HEIGHT(container, allocation);
1416 
1417 	max_icon_width = max_text_width = 0.0;
1418 	max_icon_height = max_text_height = 0.0;
1419 	max_bounds_height = 0.0;
1420 
1421 	get_max_icon_dimensions (icons, NULL,
1422 				   &max_icon_width, &max_icon_height,
1423 				   &max_text_width, &max_text_height,
1424 				   &max_bounds_height);
1425 
1426 	max_width = max_icon_width + max_text_width;
1427 	max_height = MAX (max_icon_height, max_text_height);
1428 	max_height_with_borders = ICON_PAD_TOP + max_height;
1429 
1430 	max_bounds_height_with_borders = ICON_PAD_TOP + max_bounds_height;
1431 
1432 	line_height = ICON_PAD_TOP;
1433 	line_start = icons;
1434 	x = 0;
1435 	i = 0;
1436 
1437 	max_width_in_column = 0.0;
1438 
1439 	for (p = icons; p != NULL; p = p->next) {
1440 		icon = p->data;
1441 
1442 		/* If this icon doesn't fit, it's time to lay out the column that's queued up. */
1443 
1444 		/* We use the bounds height here, since for wrapping we also want to consider
1445 		 * overlapping emblems at the bottom. We may wrap a little bit too early since
1446 		 * the icon with the max. bounds height may actually not be in the last row, but
1447 		 * it is better than visual glitches
1448 		 */
1449 		if (line_start != p && line_height + (max_bounds_height_with_borders-1) >= canvas_height ) {
1450 			x += ICON_PAD_LEFT;
1451 
1452 			/* correctly set (per-column) width */
1453 			for (i = 0; i < (int) positions->len; i++) {
1454 				position = &g_array_index (positions, IconPositions, i);
1455 				position->width = max_width_in_column;
1456 			}
1457 
1458 			lay_down_one_column (container, line_start, p, x, CONTAINER_PAD_TOP, max_height_with_borders, positions);
1459 
1460 			/* Advance to next column. */
1461 			x += max_width_in_column + ICON_PAD_RIGHT;
1462 
1463 			line_height = ICON_PAD_TOP;
1464 			line_start = p;
1465 			i = 0;
1466 
1467 			max_width_in_column = 0;
1468 		}
1469 
1470 		icon_bounds = nautilus_canvas_item_get_icon_rectangle (icon->item);
1471 		text_bounds = nautilus_canvas_item_get_text_rectangle (icon->item, TRUE);
1472 
1473 		max_width_in_column = MAX (max_width_in_column,
1474 					   ceil (icon_bounds.x1 - icon_bounds.x0) +
1475 					   ceil (text_bounds.x1 - text_bounds.x0));
1476 
1477 		g_array_set_size (positions, i + 1);
1478 		position = &g_array_index (positions, IconPositions, i++);
1479 
1480 		position->width = max_width;
1481 		position->height = max_height;
1482 		position->y_offset = ICON_PAD_TOP;
1483 		position->x_offset = ICON_PAD_LEFT;
1484 
1485 		position->x_offset += max_icon_width - ceil (icon_bounds.x1 - icon_bounds.x0);
1486 
1487 		height = MAX (ceil (icon_bounds.y1 - icon_bounds.y0), ceil(text_bounds.y1 - text_bounds.y0));
1488 		position->y_offset += (max_height - height) / 2;
1489 
1490 		/* Add this icon. */
1491 		line_height += max_height_with_borders;
1492 	}
1493 
1494 	/* Lay down that last column of icons. */
1495 	if (line_start != NULL) {
1496 		x += ICON_PAD_LEFT;
1497 		lay_down_one_column (container, line_start, NULL, x, CONTAINER_PAD_TOP, max_height_with_borders, positions);
1498 	}
1499 
1500 	g_array_free (positions, TRUE);
1501 }
1502 
1503 static void
1504 snap_position (NautilusCanvasContainer *container,
1505 	       NautilusCanvasIcon *icon,
1506 	       int *x, int *y)
1507 {
1508 	int center_x;
1509 	int baseline_y;
1510 	int icon_width;
1511 	int icon_height;
1512 	int total_width;
1513 	int total_height;
1514 	EelDRect canvas_position;
1515 	GtkAllocation allocation;
1516 	
1517 	canvas_position = nautilus_canvas_item_get_icon_rectangle (icon->item);
1518 	icon_width = canvas_position.x1 - canvas_position.x0;
1519 	icon_height = canvas_position.y1 - canvas_position.y0;
1520 
1521 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1522 	total_width = CANVAS_WIDTH (container, allocation);
1523 	total_height = CANVAS_HEIGHT (container, allocation);
1524 
1525 	if (nautilus_canvas_container_is_layout_rtl (container))
1526 		*x = get_mirror_x_position (container, icon, *x);
1527 
1528 	if (*x + icon_width / 2 < DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X) {
1529 		*x = DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X - icon_width / 2;
1530 	}
1531 
1532 	if (*x + icon_width / 2 > total_width - (DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X)) {
1533 		*x = total_width - (DESKTOP_PAD_HORIZONTAL + SNAP_SIZE_X + (icon_width / 2));
1534 	}
1535 
1536 	if (*y + icon_height < DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y) {
1537 		*y = DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y - icon_height;
1538 	}
1539 
1540 	if (*y + icon_height > total_height - (DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y)) {
1541 		*y = total_height - (DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y + (icon_height / 2));
1542 	}
1543 
1544 	center_x = *x + icon_width / 2;
1545 	*x = SNAP_NEAREST_HORIZONTAL (center_x) - (icon_width / 2);
1546 	if (nautilus_canvas_container_is_layout_rtl (container)) {
1547 		*x = get_mirror_x_position (container, icon, *x);
1548 	}
1549 
1550 
1551 	/* Find the grid position vertically and place on the proper baseline */
1552 	baseline_y = *y + icon_height;
1553 	baseline_y = SNAP_NEAREST_VERTICAL (baseline_y);
1554 	*y = baseline_y - icon_height;
1555 }
1556 
1557 static int
1558 compare_icons_by_position (gconstpointer a, gconstpointer b)
1559 {
1560 	NautilusCanvasIcon *icon_a, *icon_b;
1561 	int x1, y1, x2, y2;
1562 	int center_a;
1563 	int center_b;
1564 
1565 	icon_a = (NautilusCanvasIcon *)a;
1566 	icon_b = (NautilusCanvasIcon *)b;
1567 
1568 	icon_get_bounding_box (icon_a, &x1, &y1, &x2, &y2,
1569 				 BOUNDS_USAGE_FOR_DISPLAY);
1570 	center_a = x1 + (x2 - x1) / 2;
1571 	icon_get_bounding_box (icon_b, &x1, &y1, &x2, &y2,
1572 				 BOUNDS_USAGE_FOR_DISPLAY);
1573 	center_b = x1 + (x2 - x1) / 2;
1574 
1575 	return center_a == center_b ?
1576 		icon_a->y - icon_b->y :
1577 		center_a - center_b;
1578 }
1579 
1580 static PlacementGrid *
1581 placement_grid_new (NautilusCanvasContainer *container, gboolean tight)
1582 {
1583 	PlacementGrid *grid;
1584 	int width, height;
1585 	int num_columns;
1586 	int num_rows;
1587 	int i;
1588 	GtkAllocation allocation;
1589 
1590 	/* Get container dimensions */
1591 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1592 	width  = CANVAS_WIDTH(container, allocation);
1593 	height = CANVAS_HEIGHT(container, allocation);
1594 
1595 	num_columns = width / SNAP_SIZE_X;
1596 	num_rows = height / SNAP_SIZE_Y;
1597 	
1598 	if (num_columns == 0 || num_rows == 0) {
1599 		return NULL;
1600 	}
1601 
1602 	grid = g_new0 (PlacementGrid, 1);
1603 	grid->tight = tight;
1604 	grid->num_columns = num_columns;
1605 	grid->num_rows = num_rows;
1606 
1607 	grid->grid_memory = g_new0 (int, (num_rows * num_columns));
1608 	grid->icon_grid = g_new0 (int *, num_columns);
1609 	
1610 	for (i = 0; i < num_columns; i++) {
1611 		grid->icon_grid[i] = grid->grid_memory + (i * num_rows);
1612 	}
1613 	
1614 	return grid;
1615 }
1616 
1617 static void
1618 placement_grid_free (PlacementGrid *grid)
1619 {
1620 	g_free (grid->icon_grid);
1621 	g_free (grid->grid_memory);
1622 	g_free (grid);
1623 }
1624 
1625 static gboolean
1626 placement_grid_position_is_free (PlacementGrid *grid, EelIRect pos)
1627 {
1628 	int x, y;
1629 	
1630 	g_assert (pos.x0 >= 0 && pos.x0 < grid->num_columns);
1631 	g_assert (pos.y0 >= 0 && pos.y0 < grid->num_rows);
1632 	g_assert (pos.x1 >= 0 && pos.x1 < grid->num_columns);
1633 	g_assert (pos.y1 >= 0 && pos.y1 < grid->num_rows);
1634 
1635 	for (x = pos.x0; x <= pos.x1; x++) {
1636 		for (y = pos.y0; y <= pos.y1; y++) {
1637 			if (grid->icon_grid[x][y] != 0) {
1638 				return FALSE;
1639 			}
1640 		}
1641 	}
1642 
1643 	return TRUE;
1644 }
1645 
1646 static void
1647 placement_grid_mark (PlacementGrid *grid, EelIRect pos)
1648 {
1649 	int x, y;
1650 	
1651 	g_assert (pos.x0 >= 0 && pos.x0 < grid->num_columns);
1652 	g_assert (pos.y0 >= 0 && pos.y0 < grid->num_rows);
1653 	g_assert (pos.x1 >= 0 && pos.x1 < grid->num_columns);
1654 	g_assert (pos.y1 >= 0 && pos.y1 < grid->num_rows);
1655 
1656 	for (x = pos.x0; x <= pos.x1; x++) {
1657 		for (y = pos.y0; y <= pos.y1; y++) {
1658 			grid->icon_grid[x][y] = 1;
1659 		}
1660 	}
1661 }
1662 
1663 static void
1664 canvas_position_to_grid_position (PlacementGrid *grid,
1665 				  EelIRect canvas_position,
1666 				  EelIRect *grid_position)
1667 {
1668 	/* The first causes minimal moving around during a snap, but
1669 	 * can end up with partially overlapping icons.  The second one won't
1670 	 * allow any overlapping, but can cause more movement to happen 
1671 	 * during a snap. */
1672 	if (grid->tight) {
1673 		grid_position->x0 = ceil ((double)(canvas_position.x0 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1674 		grid_position->y0 = ceil ((double)(canvas_position.y0 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1675 		grid_position->x1 = floor ((double)(canvas_position.x1 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1676 		grid_position->y1 = floor ((double)(canvas_position.y1 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1677 	} else {
1678 		grid_position->x0 = floor ((double)(canvas_position.x0 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1679 		grid_position->y0 = floor ((double)(canvas_position.y0 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1680 		grid_position->x1 = floor ((double)(canvas_position.x1 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE_X);
1681 		grid_position->y1 = floor ((double)(canvas_position.y1 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE_Y);
1682 	}
1683 
1684 	grid_position->x0 = CLAMP (grid_position->x0, 0, grid->num_columns - 1);
1685 	grid_position->y0 = CLAMP (grid_position->y0, 0, grid->num_rows - 1);
1686 	grid_position->x1 = CLAMP (grid_position->x1, grid_position->x0, grid->num_columns - 1);
1687 	grid_position->y1 = CLAMP (grid_position->y1, grid_position->y0, grid->num_rows - 1);
1688 }
1689 
1690 static void
1691 placement_grid_mark_icon (PlacementGrid *grid, NautilusCanvasIcon *icon)
1692 {
1693 	EelIRect canvas_pos;
1694 	EelIRect grid_pos;
1695 	
1696 	icon_get_bounding_box (icon,
1697 				 &canvas_pos.x0, &canvas_pos.y0,
1698 				 &canvas_pos.x1, &canvas_pos.y1,
1699 				 BOUNDS_USAGE_FOR_LAYOUT);
1700 	canvas_position_to_grid_position (grid, 
1701 					  canvas_pos,
1702 					  &grid_pos);
1703 	placement_grid_mark (grid, grid_pos);
1704 }
1705 
1706 static void
1707 find_empty_location (NautilusCanvasContainer *container,
1708 		     PlacementGrid *grid,
1709 		     NautilusCanvasIcon *icon,
1710 		     int start_x,
1711 		     int start_y,
1712 		     int *x, 
1713 		     int *y)
1714 {
1715 	double icon_width, icon_height;
1716 	int canvas_width;
1717 	int canvas_height;
1718 	int height_for_bound_check;
1719 	EelIRect icon_position;
1720 	EelDRect pixbuf_rect;
1721 	gboolean collision;
1722 	GtkAllocation allocation;
1723 
1724 	/* Get container dimensions */
1725 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1726 	canvas_width  = CANVAS_WIDTH(container, allocation);
1727 	canvas_height = CANVAS_HEIGHT(container, allocation);
1728 
1729 	icon_get_bounding_box (icon,
1730 				 &icon_position.x0, &icon_position.y0,
1731 				 &icon_position.x1, &icon_position.y1,
1732 				 BOUNDS_USAGE_FOR_LAYOUT);
1733 	icon_width = icon_position.x1 - icon_position.x0;
1734 	icon_height = icon_position.y1 - icon_position.y0;
1735 
1736 	icon_get_bounding_box (icon,
1737 				 NULL, &icon_position.y0,
1738 				 NULL, &icon_position.y1,
1739 				 BOUNDS_USAGE_FOR_ENTIRE_ITEM);
1740 	height_for_bound_check = icon_position.y1 - icon_position.y0;
1741 
1742 	pixbuf_rect = nautilus_canvas_item_get_icon_rectangle (icon->item);
1743 	
1744 	/* Start the icon on a grid location */
1745 	snap_position (container, icon, &start_x, &start_y);
1746 
1747 	icon_position.x0 = start_x;
1748 	icon_position.y0 = start_y;
1749 	icon_position.x1 = icon_position.x0 + icon_width;
1750 	icon_position.y1 = icon_position.y0 + icon_height;
1751 
1752 	do {
1753 		EelIRect grid_position;
1754 		gboolean need_new_column;
1755 
1756 		collision = FALSE;
1757 		
1758 		canvas_position_to_grid_position (grid,
1759 						  icon_position,
1760 						  &grid_position);
1761 
1762 		need_new_column = icon_position.y0 + height_for_bound_check + DESKTOP_PAD_VERTICAL > canvas_height;
1763 
1764 		if (need_new_column ||
1765 		    !placement_grid_position_is_free (grid, grid_position)) {
1766 			icon_position.y0 += SNAP_SIZE_Y;
1767 			icon_position.y1 = icon_position.y0 + icon_height;
1768 			
1769 			if (need_new_column) {
1770 				/* Move to the next column */
1771 				icon_position.y0 = DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y - (pixbuf_rect.y1 - pixbuf_rect.y0);
1772 				while (icon_position.y0 < DESKTOP_PAD_VERTICAL) {
1773 					icon_position.y0 += SNAP_SIZE_Y;
1774 				}
1775 				icon_position.y1 = icon_position.y0 + icon_height;
1776 				
1777 				icon_position.x0 += SNAP_SIZE_X;
1778 				icon_position.x1 = icon_position.x0 + icon_width;
1779 			}
1780 				
1781 			collision = TRUE;
1782 		}
1783 	} while (collision && (icon_position.x1 < canvas_width));
1784 
1785 	*x = icon_position.x0;
1786 	*y = icon_position.y0;
1787 }
1788 
1789 static void
1790 align_icons (NautilusCanvasContainer *container)
1791 {
1792 	GList *unplaced_icons;
1793 	GList *l;
1794 	PlacementGrid *grid;
1795 
1796 	unplaced_icons = g_list_copy (container->details->icons);
1797 	
1798 	unplaced_icons = g_list_sort (unplaced_icons, 
1799 					compare_icons_by_position);
1800 
1801 	if (nautilus_canvas_container_is_layout_rtl (container)) {
1802 		unplaced_icons = g_list_reverse (unplaced_icons);
1803 	}
1804 
1805 	grid = placement_grid_new (container, TRUE);
1806 
1807 	if (!grid) {
1808 		return;
1809 	}
1810 
1811 	for (l = unplaced_icons; l != NULL; l = l->next) {
1812 		NautilusCanvasIcon *icon;
1813 		int x, y;
1814 
1815 		icon = l->data;
1816 		x = icon->saved_ltr_x;
1817 		y = icon->y;
1818 		find_empty_location (container, grid, 
1819 				     icon, x, y, &x, &y);
1820 
1821 		icon_set_position (icon, x, y);
1822 		icon->saved_ltr_x = icon->x;
1823 		placement_grid_mark_icon (grid, icon);
1824 	}
1825 
1826 	g_list_free (unplaced_icons);
1827 
1828 	placement_grid_free (grid);
1829 
1830 	if (nautilus_canvas_container_is_layout_rtl (container)) {
1831 		nautilus_canvas_container_set_rtl_positions (container);
1832 	}
1833 }
1834 
1835 static double
1836 get_mirror_x_position (NautilusCanvasContainer *container, NautilusCanvasIcon *icon, double x)
1837 {
1838 	EelDRect icon_bounds;
1839 	GtkAllocation allocation;
1840 
1841 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1842 	icon_bounds = nautilus_canvas_item_get_icon_rectangle (icon->item);
1843 
1844 	return CANVAS_WIDTH(container, allocation) - x - (icon_bounds.x1 - icon_bounds.x0);
1845 }
1846 
1847 static void
1848 nautilus_canvas_container_set_rtl_positions (NautilusCanvasContainer *container)
1849 {
1850 	GList *l;
1851 	NautilusCanvasIcon *icon;
1852 	double x;
1853 
1854 	if (!container->details->icons) {
1855 		return;
1856 	}
1857 
1858 	for (l = container->details->icons; l != NULL; l = l->next) {
1859 		icon = l->data;
1860 		x = get_mirror_x_position (container, icon, icon->saved_ltr_x);
1861 		icon_set_position (icon, x, icon->y);
1862 	}
1863 }
1864 
1865 static void
1866 lay_down_icons_vertical_desktop (NautilusCanvasContainer *container, GList *icons)
1867 {
1868 	GList *p, *placed_icons, *unplaced_icons;
1869 	int total, new_length, placed;
1870 	NautilusCanvasIcon *icon;
1871 	int height, max_width, column_width, icon_width, icon_height;
1872 	int x, y, x1, x2, y1, y2;
1873 	EelDRect icon_rect;
1874 	GtkAllocation allocation;
1875 
1876 	/* Get container dimensions */
1877 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
1878 	height = CANVAS_HEIGHT(container, allocation);
1879 
1880 	/* Determine which icons have and have not been placed */
1881 	placed_icons = NULL;
1882 	unplaced_icons = NULL;
1883 	
1884 	total = g_list_length (container->details->icons);
1885 	new_length = g_list_length (icons);
1886 	placed = total - new_length;
1887 	if (placed > 0) {
1888 		PlacementGrid *grid;
1889 		/* Add only placed icons in list */
1890 		for (p = container->details->icons; p != NULL; p = p->next) {
1891 			icon = p->data;
1892 			if (icon_is_positioned (icon)) {
1893 				icon_set_position(icon, icon->saved_ltr_x, icon->y);
1894 				placed_icons = g_list_prepend (placed_icons, icon);
1895 			} else {
1896 				icon->x = 0;
1897 				icon->y = 0;
1898 				unplaced_icons = g_list_prepend (unplaced_icons, icon);
1899 			}
1900 		}
1901 		placed_icons = g_list_reverse (placed_icons);
1902 		unplaced_icons = g_list_reverse (unplaced_icons);
1903 
1904 		grid = placement_grid_new (container, FALSE);
1905 
1906 		if (grid) {
1907 			for (p = placed_icons; p != NULL; p = p->next) {
1908 				placement_grid_mark_icon
1909 					(grid, (NautilusCanvasIcon *)p->data);
1910 			}
1911 			
1912 			/* Place unplaced icons in the best locations */
1913 			for (p = unplaced_icons; p != NULL; p = p->next) {
1914 				icon = p->data;
1915 				
1916 				icon_rect = nautilus_canvas_item_get_icon_rectangle (icon->item);
1917 				
1918 				/* Start the icon in the first column */
1919 				x = DESKTOP_PAD_HORIZONTAL + (SNAP_SIZE_X / 2) - ((icon_rect.x1 - icon_rect.x0) / 2);
1920 				y = DESKTOP_PAD_VERTICAL + SNAP_SIZE_Y - (icon_rect.y1 - icon_rect.y0);
1921 
1922 				find_empty_location (container,
1923 						     grid,
1924 						     icon,
1925 						     x, y,
1926 						     &x, &y);
1927 				
1928 				icon_set_position (icon, x, y);
1929 				icon->saved_ltr_x = x;
1930 				placement_grid_mark_icon (grid, icon);
1931 			}
1932 
1933 			placement_grid_free (grid);
1934 		}
1935 		
1936 		g_list_free (placed_icons);
1937 		g_list_free (unplaced_icons);
1938 	} else {
1939 		/* There are no placed icons.  Just lay them down using our rules */		
1940 		x = DESKTOP_PAD_HORIZONTAL;
1941 
1942 		while (icons != NULL) {
1943 			int center_x;
1944 			int baseline;
1945 			int icon_height_for_bound_check;
1946 			gboolean should_snap;
1947 			
1948 			should_snap = container->details->keep_aligned;
1949 			
1950 			y = DESKTOP_PAD_VERTICAL;
1951 
1952 			max_width = 0;
1953 			
1954 			/* Calculate max width for column */
1955 			for (p = icons; p != NULL; p = p->next) {
1956 				icon = p->data;
1957 
1958 				icon_get_bounding_box (icon, &x1, &y1, &x2, &y2,
1959 							 BOUNDS_USAGE_FOR_LAYOUT);
1960 				icon_width = x2 - x1;
1961 				icon_height = y2 - y1;
1962 
1963 				icon_get_bounding_box (icon, NULL, &y1, NULL, &y2,
1964 						       BOUNDS_USAGE_FOR_ENTIRE_ITEM);
1965 				icon_height_for_bound_check = y2 - y1;
1966 
1967 				if (should_snap) {
1968 					/* Snap the baseline to a grid position */
1969 					icon_rect = nautilus_canvas_item_get_icon_rectangle (icon->item);
1970 					baseline = y + (icon_rect.y1 - icon_rect.y0);
1971 					baseline = SNAP_CEIL_VERTICAL (baseline);
1972 					y = baseline - (icon_rect.y1 - icon_rect.y0);
1973 				}
1974 				    
1975 				/* Check and see if we need to move to a new column */
1976 				if (y != DESKTOP_PAD_VERTICAL && y + icon_height_for_bound_check > height) {
1977 					break;
1978 				}
1979 
1980 				if (max_width < icon_width) {
1981 					max_width = icon_width;
1982 				}
1983 				
1984 				y += icon_height + DESKTOP_PAD_VERTICAL;
1985 			}
1986 
1987 			y = DESKTOP_PAD_VERTICAL;
1988 
1989 			center_x = x + max_width / 2;
1990 			column_width = max_width;
1991 			if (should_snap) {
1992 				/* Find the grid column to center on */
1993 				center_x = SNAP_CEIL_HORIZONTAL (center_x);
1994 				column_width = (center_x - x) + (max_width / 2);
1995 			}
1996 			
1997 			/* Lay out column */
1998 			for (p = icons; p != NULL; p = p->next) {
1999 				icon = p->data;
2000 				icon_get_bounding_box (icon, &x1, &y1, &x2, &y2,
2001 							 BOUNDS_USAGE_FOR_LAYOUT);
2002 				icon_height = y2 - y1;
2003 
2004 				icon_get_bounding_box (icon, NULL, &y1, NULL, &y2,
2005 							 BOUNDS_USAGE_FOR_ENTIRE_ITEM);
2006 				icon_height_for_bound_check = y2 - y1;
2007 				
2008 				icon_rect = nautilus_canvas_item_get_icon_rectangle (icon->item);
2009 
2010 				if (should_snap) {
2011 					baseline = y + (icon_rect.y1 - icon_rect.y0);
2012 					baseline = SNAP_CEIL_VERTICAL (baseline);
2013 					y = baseline - (icon_rect.y1 - icon_rect.y0);
2014 				}
2015 				
2016 				/* Check and see if we need to move to a new column */
2017 				if (y != DESKTOP_PAD_VERTICAL && y > height - icon_height_for_bound_check &&
2018 				    /* Make sure we lay out at least one icon per column, to make progress */
2019 				    p != icons) {
2020 					x += column_width + DESKTOP_PAD_HORIZONTAL;
2021 					break;
2022 				}
2023 				
2024 				icon_set_position (icon,
2025 						     center_x - (icon_rect.x1 - icon_rect.x0) / 2,
2026 						     y);
2027 				
2028 				icon->saved_ltr_x = icon->x;
2029 				y += icon_height + DESKTOP_PAD_VERTICAL;
2030 			}
2031 			icons = p;
2032 		}
2033 	}
2034 
2035 	/* These modes are special. We freeze all of our positions
2036 	 * after we do the layout.
2037 	 */
2038 	/* FIXME bugzilla.gnome.org 42478: 
2039 	 * This should not be tied to the direction of layout.
2040 	 * It should be a separate switch.
2041 	 */
2042 	nautilus_canvas_container_freeze_icon_positions (container);
2043 }
2044 
2045 
2046 static void
2047 lay_down_icons (NautilusCanvasContainer *container, GList *icons, double start_y)
2048 {
2049 	switch (container->details->layout_mode)
2050 		{
2051 		case NAUTILUS_CANVAS_LAYOUT_L_R_T_B:
2052 		case NAUTILUS_CANVAS_LAYOUT_R_L_T_B:
2053 			lay_down_icons_horizontal (container, icons, start_y);
2054 			break;
2055 		
2056 		case NAUTILUS_CANVAS_LAYOUT_T_B_L_R:
2057 		case NAUTILUS_CANVAS_LAYOUT_T_B_R_L:
2058 			if (nautilus_canvas_container_get_is_desktop (container)) {
2059 				lay_down_icons_vertical_desktop (container, icons);
2060 			} else {
2061 				lay_down_icons_vertical (container, icons, start_y);
2062 			}
2063 			break;
2064 		
2065 		default:
2066 			g_assert_not_reached ();
2067 		}
2068 }
2069 
2070 static void
2071 redo_layout_internal (NautilusCanvasContainer *container)
2072 {
2073 	finish_adding_new_icons (container);
2074 
2075 	/* Don't do any re-laying-out during stretching. Later we
2076 	 * might add smart logic that does this and leaves room for
2077 	 * the stretched icon, but if we do it we want it to be fast
2078 	 * and only re-lay-out when it's really needed.
2079 	 */
2080 	if (container->details->auto_layout
2081 	    && container->details->drag_state != DRAG_STATE_STRETCH) {
2082 		if (container->details->needs_resort) {
2083 			resort (container);
2084 			container->details->needs_resort = FALSE;
2085 		}
2086 		lay_down_icons (container, container->details->icons, 0);
2087 	}
2088 
2089 	if (nautilus_canvas_container_is_layout_rtl (container)) {
2090 		nautilus_canvas_container_set_rtl_positions (container);
2091 	}
2092 
2093 	nautilus_canvas_container_update_scroll_region (container);
2094 
2095 	process_pending_icon_to_reveal (container);
2096 	process_pending_icon_to_rename (container);
2097 	nautilus_canvas_container_update_visible_icons (container);
2098 }
2099 
2100 static gboolean
2101 redo_layout_callback (gpointer callback_data)
2102 {
2103 	NautilusCanvasContainer *container;
2104 
2105 	container = NAUTILUS_CANVAS_CONTAINER (callback_data);
2106 	redo_layout_internal (container);
2107 	container->details->idle_id = 0;
2108 
2109 	return FALSE;
2110 }
2111 
2112 static void
2113 unschedule_redo_layout (NautilusCanvasContainer *container)
2114 {
2115         if (container->details->idle_id != 0) {
2116 		g_source_remove (container->details->idle_id);
2117 		container->details->idle_id = 0;
2118 	}
2119 }
2120 
2121 static void
2122 schedule_redo_layout (NautilusCanvasContainer *container)
2123 {
2124 	if (container->details->idle_id == 0
2125 	    && container->details->has_been_allocated) {
2126 		container->details->idle_id = g_idle_add
2127 			(redo_layout_callback, container);
2128 	}
2129 }
2130 
2131 static void
2132 redo_layout (NautilusCanvasContainer *container)
2133 {
2134 	unschedule_redo_layout (container);
2135 	redo_layout_internal (container);
2136 }
2137 
2138 static void
2139 reload_icon_positions (NautilusCanvasContainer *container)
2140 {
2141 	GList *p, *no_position_icons;
2142 	NautilusCanvasIcon *icon;
2143 	gboolean have_stored_position;
2144 	NautilusCanvasPosition position;
2145 	EelDRect bounds;
2146 	double bottom;
2147 	EelCanvasItem *item;
2148 
2149 	g_assert (!container->details->auto_layout);
2150 
2151 	resort (container);
2152 
2153 	no_position_icons = NULL;
2154 
2155 	/* Place all the icons with positions. */
2156 	bottom = 0;
2157 	for (p = container->details->icons; p != NULL; p = p->next) {
2158 		icon = p->data;
2159 
2160 		have_stored_position = FALSE;
2161 		g_signal_emit (container,
2162 			       signals[GET_STORED_ICON_POSITION], 0,
2163 			       icon->data,
2164 			       &position,
2165 			       &have_stored_position);
2166 		if (have_stored_position) {
2167 			icon_set_position (icon, position.x, position.y);
2168 			item = EEL_CANVAS_ITEM (icon->item);
2169 			nautilus_canvas_item_get_bounds_for_layout (icon->item,
2170 									   &bounds.x0,
2171 									   &bounds.y0,
2172 									   &bounds.x1,
2173 									   &bounds.y1);
2174 			eel_canvas_item_i2w (item->parent,
2175 					     &bounds.x0,
2176 					     &bounds.y0);
2177 			eel_canvas_item_i2w (item->parent,
2178 					     &bounds.x1,
2179 					     &bounds.y1);
2180 			if (bounds.y1 > bottom) {
2181 				bottom = bounds.y1;
2182 			}
2183 		} else {
2184 			no_position_icons = g_list_prepend (no_position_icons, icon);
2185 		}
2186 	}
2187 	no_position_icons = g_list_reverse (no_position_icons);
2188 
2189 	/* Place all the other icons. */
2190 	lay_down_icons (container, no_position_icons, bottom + ICON_PAD_BOTTOM);
2191 	g_list_free (no_position_icons);
2192 }
2193 
2194 /* Container-level icon handling functions.  */
2195 
2196 static gboolean
2197 button_event_modifies_selection (GdkEventButton *event)
2198 {
2199 	return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
2200 }
2201 
2202 /* invalidate the cached label sizes for all the icons */
2203 static void
2204 invalidate_label_sizes (NautilusCanvasContainer *container)
2205 {
2206 	GList *p;
2207 	NautilusCanvasIcon *icon;
2208 	
2209 	for (p = container->details->icons; p != NULL; p = p->next) {
2210 		icon = p->data;
2211 
2212 		nautilus_canvas_item_invalidate_label_size (icon->item);		
2213 	}
2214 }
2215 
2216 /* invalidate the entire labels (i.e. their attributes) for all the icons */
2217 static void
2218 invalidate_labels (NautilusCanvasContainer *container)
2219 {
2220 	GList *p;
2221 	NautilusCanvasIcon *icon;
2222 	
2223 	for (p = container->details->icons; p != NULL; p = p->next) {
2224 		icon = p->data;
2225 
2226 		nautilus_canvas_item_invalidate_label (icon->item);		
2227 	}
2228 }
2229 
2230 static gboolean
2231 select_range (NautilusCanvasContainer *container,
2232 	      NautilusCanvasIcon *icon1,
2233 	      NautilusCanvasIcon *icon2,
2234 	      gboolean unselect_outside_range)
2235 {
2236 	gboolean selection_changed;
2237 	GList *p;
2238 	NautilusCanvasIcon *icon;
2239 	NautilusCanvasIcon *unmatched_icon;
2240 	gboolean select;
2241 
2242 	selection_changed = FALSE;
2243 
2244 	unmatched_icon = NULL;
2245 	select = FALSE;
2246 	for (p = container->details->icons; p != NULL; p = p->next) {
2247 		icon = p->data;
2248 
2249 		if (unmatched_icon == NULL) {
2250 			if (icon == icon1) {
2251 				unmatched_icon = icon2;
2252 				select = TRUE;
2253 			} else if (icon == icon2) {
2254 				unmatched_icon = icon1;
2255 				select = TRUE;
2256 			}
2257 		}
2258 		
2259 		if (select || unselect_outside_range) {
2260 			selection_changed |= icon_set_selected
2261 				(container, icon, select);
2262 		}
2263 
2264 		if (unmatched_icon != NULL && icon == unmatched_icon) {
2265 			select = FALSE;
2266 		}
2267 		
2268 	}
2269 	
2270 	if (selection_changed && icon2 != NULL) {
2271 		emit_atk_focus_tracker_notify (icon2);
2272 	}
2273 	return selection_changed;
2274 }
2275 
2276 
2277 static gboolean
2278 select_one_unselect_others (NautilusCanvasContainer *container,
2279 			    NautilusCanvasIcon *icon_to_select)
2280 {
2281 	gboolean selection_changed;
2282 	GList *p;
2283 	NautilusCanvasIcon *icon;
2284 
2285 	selection_changed = FALSE;
2286 	
2287 	for (p = container->details->icons; p != NULL; p = p->next) {
2288 		icon = p->data;
2289 
2290 		selection_changed |= icon_set_selected
2291 			(container, icon, icon == icon_to_select);
2292 	}
2293 	
2294 	if (selection_changed && icon_to_select != NULL) {
2295 		emit_atk_focus_tracker_notify (icon_to_select);
2296 		reveal_icon (container, icon_to_select);
2297 	}
2298 	return selection_changed;
2299 }
2300 
2301 static gboolean
2302 unselect_all (NautilusCanvasContainer *container)
2303 {
2304 	return select_one_unselect_others (container, NULL);
2305 }
2306 
2307 void
2308 nautilus_canvas_container_move_icon (NautilusCanvasContainer *container,
2309 				       NautilusCanvasIcon *icon,
2310 				       int x, int y,
2311 				       double scale,
2312 				       gboolean raise,
2313 				       gboolean snap,
2314 				       gboolean update_position)
2315 {
2316 	NautilusCanvasContainerDetails *details;
2317 	gboolean emit_signal;
2318 	NautilusCanvasPosition position;
2319 	
2320 	details = container->details;
2321 	
2322 	emit_signal = FALSE;
2323 	
2324 	if (icon == get_icon_being_renamed (container)) {
2325 		end_renaming_mode (container, TRUE);
2326 	}
2327 
2328 	if (scale != icon->scale) {
2329 		icon->scale = scale;
2330 		nautilus_canvas_container_update_icon (container, icon);
2331 		if (update_position) {
2332 			redo_layout (container); 
2333 			emit_signal = TRUE;
2334 		}
2335 	}
2336 
2337 	if (!details->auto_layout) {
2338 		if (details->keep_aligned && snap) {
2339 			snap_position (container, icon, &x, &y);
2340 		}
2341 
2342 		if (x != icon->x || y != icon->y) {
2343 			icon_set_position (icon, x, y);
2344 			emit_signal = update_position;
2345 		}
2346 
2347 		icon->saved_ltr_x = nautilus_canvas_container_is_layout_rtl (container) ? get_mirror_x_position (container, icon, icon->x) : icon->x;
2348 	}
2349 	
2350 	if (emit_signal) {
2351 		position.x = icon->saved_ltr_x;
2352 		position.y = icon->y;
2353 		position.scale = scale;
2354 		g_signal_emit (container,
2355 			       signals[ICON_POSITION_CHANGED], 0,
2356 			       icon->data, &position);
2357 	}
2358 	
2359 	if (raise) {
2360 		icon_raise (icon);
2361 	}
2362 
2363 	/* FIXME bugzilla.gnome.org 42474: 
2364 	 * Handling of the scroll region is inconsistent here. In
2365 	 * the scale-changing case, redo_layout is called, which updates the
2366 	 * scroll region appropriately. In other cases, it's up to the
2367 	 * caller to make sure the scroll region is updated. This could
2368 	 * lead to hard-to-track-down bugs.
2369 	 */
2370 }
2371 
2372 /* Implementation of rubberband selection.  */
2373 static void
2374 rubberband_select (NautilusCanvasContainer *container,
2375 		   const EelDRect *previous_rect,
2376 		   const EelDRect *current_rect)
2377 {
2378 	GList *p;
2379 	gboolean selection_changed, is_in, canvas_rect_calculated;
2380 	NautilusCanvasIcon *icon;
2381 	EelIRect canvas_rect;
2382 	EelCanvas *canvas;
2383 			
2384 	selection_changed = FALSE;
2385 	canvas_rect_calculated = FALSE;
2386 
2387 	for (p = container->details->icons; p != NULL; p = p->next) {
2388 		icon = p->data;
2389 		
2390 		if (!canvas_rect_calculated) {
2391 			/* Only do this calculation once, since all the canvas items
2392 			 * we are interating are in the same coordinate space
2393 			 */
2394 			canvas = EEL_CANVAS_ITEM (icon->item)->canvas;
2395 			eel_canvas_w2c (canvas,
2396 					current_rect->x0,
2397 					current_rect->y0,
2398 					&canvas_rect.x0,
2399 					&canvas_rect.y0);
2400 			eel_canvas_w2c (canvas,
2401 					current_rect->x1,
2402 					current_rect->y1,
2403 					&canvas_rect.x1,
2404 					&canvas_rect.y1);
2405 			canvas_rect_calculated = TRUE;
2406 		}
2407 		
2408 		is_in = nautilus_canvas_item_hit_test_rectangle (icon->item, canvas_rect);
2409 
2410 		selection_changed |= icon_set_selected
2411 			(container, icon,
2412 			 is_in ^ icon->was_selected_before_rubberband);
2413 	}
2414 
2415 	if (selection_changed) {
2416 		g_signal_emit (container,
2417 			       signals[SELECTION_CHANGED], 0);
2418 	}
2419 }
2420 
2421 static int
2422 rubberband_timeout_callback (gpointer data)
2423 {
2424 	NautilusCanvasContainer *container;
2425 	GtkWidget *widget;
2426 	NautilusCanvasRubberbandInfo *band_info;
2427 	int x, y;
2428 	double x1, y1, x2, y2;
2429 	double world_x, world_y;
2430 	int x_scroll, y_scroll;
2431 	int adj_x, adj_y;
2432 	gboolean adj_changed;
2433 	GtkAllocation allocation;
2434 	
2435 	EelDRect selection_rect;
2436 
2437 	widget = GTK_WIDGET (data);
2438 	container = NAUTILUS_CANVAS_CONTAINER (data);
2439 	band_info = &container->details->rubberband_info;
2440 
2441 	g_assert (band_info->timer_id != 0);
2442 
2443 	adj_changed = FALSE;
2444 	gtk_widget_get_allocation (widget, &allocation);
2445 
2446 	adj_x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
2447 	if (adj_x != band_info->last_adj_x) {
2448 		band_info->last_adj_x = adj_x;
2449 		adj_changed = TRUE;
2450 	}
2451 
2452 	adj_y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
2453 	if (adj_y != band_info->last_adj_y) {
2454 		band_info->last_adj_y = adj_y;
2455 		adj_changed = TRUE;
2456 	}
2457 
2458 	gdk_window_get_device_position (gtk_widget_get_window (widget),
2459 					gdk_device_manager_get_client_pointer (
2460 									       gdk_display_get_device_manager (
2461 													       gtk_widget_get_display (widget))),
2462 					&x, &y, NULL);
2463 
2464 	if (x < RUBBERBAND_SCROLL_THRESHOLD) {
2465 		x_scroll = x - RUBBERBAND_SCROLL_THRESHOLD;
2466 		x = 0;
2467 	} else if (x >= allocation.width - RUBBERBAND_SCROLL_THRESHOLD) {
2468 		x_scroll = x - allocation.width + RUBBERBAND_SCROLL_THRESHOLD + 1;
2469 		x = allocation.width - 1;
2470 	} else {
2471 		x_scroll = 0;
2472 	}
2473 
2474 	if (y < RUBBERBAND_SCROLL_THRESHOLD) {
2475 		y_scroll = y - RUBBERBAND_SCROLL_THRESHOLD;
2476 		y = 0;
2477 	} else if (y >= allocation.height - RUBBERBAND_SCROLL_THRESHOLD) {
2478 		y_scroll = y - allocation.height + RUBBERBAND_SCROLL_THRESHOLD + 1;
2479 		y = allocation.height - 1;
2480 	} else {
2481 		y_scroll = 0;
2482 	}
2483 
2484 	if (y_scroll == 0 && x_scroll == 0
2485 	    && (int) band_info->prev_x == x && (int) band_info->prev_y == y && !adj_changed) {
2486 		return TRUE;
2487 	}
2488 
2489 	nautilus_canvas_container_scroll (container, x_scroll, y_scroll);
2490 
2491 	/* Remember to convert from widget to scrolled window coords */
2492 	eel_canvas_window_to_world (EEL_CANVAS (container),
2493 				    x + gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container))),
2494 				    y + gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container))),
2495 				    &world_x, &world_y);
2496 
2497 	if (world_x < band_info->start_x) {
2498 		x1 = world_x;
2499 		x2 = band_info->start_x;
2500 	} else {
2501 		x1 = band_info->start_x;
2502 		x2 = world_x;
2503 	}
2504 
2505 	if (world_y < band_info->start_y) {
2506 		y1 = world_y;
2507 		y2 = band_info->start_y;
2508 	} else {
2509 		y1 = band_info->start_y;
2510 		y2 = world_y;
2511 	}
2512 
2513 	/* Don't let the area of the selection rectangle be empty.
2514 	 * Aside from the fact that it would be funny when the rectangle disappears,
2515 	 * this also works around a crash in libart that happens sometimes when a
2516 	 * zero height rectangle is passed.
2517 	 */
2518 	x2 = MAX (x1 + 1, x2);
2519 	y2 = MAX (y1 + 1, y2);
2520 
2521 	eel_canvas_item_set
2522 		(band_info->selection_rectangle,
2523 		 "x1", x1, "y1", y1,
2524 		 "x2", x2, "y2", y2,
2525 		 NULL);
2526 
2527 	selection_rect.x0 = x1;
2528 	selection_rect.y0 = y1;
2529 	selection_rect.x1 = x2;
2530 	selection_rect.y1 = y2;
2531 
2532 	rubberband_select (container,
2533 			   &band_info->prev_rect,
2534 			   &selection_rect);
2535 	
2536 	band_info->prev_x = x;
2537 	band_info->prev_y = y;
2538 
2539 	band_info->prev_rect = selection_rect;
2540 
2541 	return TRUE;
2542 }
2543 
2544 static void
2545 start_rubberbanding (NautilusCanvasContainer *container,
2546 		     GdkEventButton *event)
2547 {
2548 	AtkObject *accessible;
2549 	NautilusCanvasContainerDetails *details;
2550 	NautilusCanvasRubberbandInfo *band_info;
2551 	GdkRGBA bg_color, border_color;
2552 	GList *p;
2553 	NautilusCanvasIcon *icon;
2554 	GtkStyleContext *context;
2555 
2556 	details = container->details;
2557 	band_info = &details->rubberband_info;
2558 
2559 	g_signal_emit (container,
2560 		       signals[BAND_SELECT_STARTED], 0);
2561 
2562 	for (p = details->icons; p != NULL; p = p->next) {
2563 		icon = p->data;
2564 		icon->was_selected_before_rubberband = icon->is_selected;
2565 	}
2566 
2567 	eel_canvas_window_to_world
2568 		(EEL_CANVAS (container), event->x, event->y,
2569 		 &band_info->start_x, &band_info->start_y);
2570 
2571 	context = gtk_widget_get_style_context (GTK_WIDGET (container));
2572 	gtk_style_context_save (context);
2573 	gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
2574 
2575 	gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg_color);
2576 	gtk_style_context_get_border_color (context, GTK_STATE_FLAG_NORMAL, &border_color);
2577 
2578 	gtk_style_context_restore (context);
2579 
2580 	band_info->selection_rectangle = eel_canvas_item_new
2581 		(eel_canvas_root
2582 		 (EEL_CANVAS (container)),
2583 		 NAUTILUS_TYPE_SELECTION_CANVAS_ITEM,
2584 		 "x1", band_info->start_x,
2585 		 "y1", band_info->start_y,
2586 		 "x2", band_info->start_x,
2587 		 "y2", band_info->start_y,
2588 		 "fill_color_rgba", &bg_color,
2589 		 "outline_color_rgba", &border_color,
2590 		 "width_pixels", 1,
2591 		 NULL);
2592 
2593 	accessible = atk_gobject_accessible_for_object
2594 		(G_OBJECT (band_info->selection_rectangle));
2595 	atk_object_set_name (accessible, "selection");
2596 	atk_object_set_description (accessible, _("The selection rectangle"));
2597 
2598 	band_info->prev_x = event->x - gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
2599 	band_info->prev_y = event->y - gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
2600 
2601 	band_info->active = TRUE;
2602 
2603 	if (band_info->timer_id == 0) {
2604 		band_info->timer_id = g_timeout_add
2605 			(RUBBERBAND_TIMEOUT_INTERVAL,
2606 			 rubberband_timeout_callback,
2607 			 container);
2608 	}
2609 
2610 	eel_canvas_item_grab (band_info->selection_rectangle,
2611 			      (GDK_POINTER_MOTION_MASK
2612 			       | GDK_BUTTON_RELEASE_MASK 
2613 			       | GDK_SCROLL_MASK),
2614 			      NULL, event->time);
2615 }
2616 
2617 static void
2618 stop_rubberbanding (NautilusCanvasContainer *container,
2619 		    guint32 time)
2620 {
2621 	NautilusCanvasRubberbandInfo *band_info;
2622 	GList *icons;
2623 	gboolean enable_animation;
2624 
2625 	band_info = &container->details->rubberband_info;
2626 
2627 	g_assert (band_info->timer_id != 0);
2628 	g_source_remove (band_info->timer_id);
2629 	band_info->timer_id = 0;
2630 
2631 	band_info->active = FALSE;
2632 
2633 	g_object_get (gtk_settings_get_default (), "gtk-enable-animations", &enable_animation, NULL);
2634 
2635 	/* Destroy this canvas item; the parent will unref it. */
2636 	eel_canvas_item_ungrab (band_info->selection_rectangle, time);
2637 	eel_canvas_item_lower_to_bottom (band_info->selection_rectangle);
2638 	if (enable_animation) {
2639 		nautilus_selection_canvas_item_fade_out (NAUTILUS_SELECTION_CANVAS_ITEM (band_info->selection_rectangle), 150);
2640 	} else {
2641 		eel_canvas_item_destroy (band_info->selection_rectangle);
2642 	}
2643 	band_info->selection_rectangle = NULL;
2644 
2645 	/* if only one item has been selected, use it as range
2646 	 * selection base (cf. handle_icon_button_press) */
2647 	icons = nautilus_canvas_container_get_selected_icons (container);
2648 	if (g_list_length (icons) == 1) {
2649 		container->details->range_selection_base_icon = icons->data;
2650 	}
2651 	g_list_free (icons);
2652 
2653 	g_signal_emit (container,
2654 		       signals[BAND_SELECT_ENDED], 0);
2655 }
2656 
2657 /* Keyboard navigation.  */
2658 
2659 typedef gboolean (* IsBetterCanvasFunction) (NautilusCanvasContainer *container,
2660 					     NautilusCanvasIcon *start_icon,
2661 					     NautilusCanvasIcon *best_so_far,
2662 					     NautilusCanvasIcon *candidate,
2663 					     void *data);
2664 
2665 static NautilusCanvasIcon *
2666 find_best_icon (NautilusCanvasContainer *container,
2667 		  NautilusCanvasIcon *start_icon,
2668 		  IsBetterCanvasFunction function,
2669 		  void *data)
2670 {
2671 	GList *p;
2672 	NautilusCanvasIcon *best, *candidate;
2673 
2674 	best = NULL;
2675 	for (p = container->details->icons; p != NULL; p = p->next) {
2676 		candidate = p->data;
2677 
2678 		if (candidate != start_icon) {
2679 			if ((* function) (container, start_icon, best, candidate, data)) {
2680 				best = candidate;
2681 			}
2682 		}
2683 	}
2684 	return best;
2685 }
2686 
2687 static NautilusCanvasIcon *
2688 find_best_selected_icon (NautilusCanvasContainer *container,
2689 			   NautilusCanvasIcon *start_icon,
2690 			   IsBetterCanvasFunction function,
2691 			   void *data)
2692 {
2693 	GList *p;
2694 	NautilusCanvasIcon *best, *candidate;
2695 
2696 	best = NULL;
2697 	for (p = container->details->icons; p != NULL; p = p->next) {
2698 		candidate = p->data;
2699 
2700 		if (candidate != start_icon && candidate->is_selected) {
2701 			if ((* function) (container, start_icon, best, candidate, data)) {
2702 				best = candidate;
2703 			}
2704 		}
2705 	}
2706 	return best;
2707 }
2708 
2709 static int
2710 compare_icons_by_uri (NautilusCanvasContainer *container,
2711 			NautilusCanvasIcon *icon_a,
2712 			NautilusCanvasIcon *icon_b)
2713 {
2714 	char *uri_a, *uri_b;
2715 	int result;
2716 
2717 	g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
2718 	g_assert (icon_a != NULL);
2719 	g_assert (icon_b != NULL);
2720 	g_assert (icon_a != icon_b);
2721 
2722 	uri_a = nautilus_canvas_container_get_icon_uri (container, icon_a);
2723 	uri_b = nautilus_canvas_container_get_icon_uri (container, icon_b);
2724 	result = strcmp (uri_a, uri_b);
2725 	g_assert (result != 0);
2726 	g_free (uri_a);
2727 	g_free (uri_b);
2728 	
2729 	return result;
2730 }
2731 
2732 static int
2733 get_cmp_point_x (NautilusCanvasContainer *container,
2734 		 EelDRect icon_rect)
2735 {
2736 	return (icon_rect.x0 + icon_rect.x1) / 2;
2737 }
2738 
2739 static int
2740 get_cmp_point_y (NautilusCanvasContainer *container,
2741 		 EelDRect icon_rect)
2742 {
2743 	return icon_rect.y1;
2744 }
2745 
2746 
2747 static int
2748 compare_icons_horizontal (NautilusCanvasContainer *container,
2749 			    NautilusCanvasIcon *icon_a,
2750 			    NautilusCanvasIcon *icon_b)
2751 {
2752 	EelDRect world_rect;
2753 	int ax, bx;
2754 
2755 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_a->item);
2756 	eel_canvas_w2c
2757 		(EEL_CANVAS (container),
2758 		 get_cmp_point_x (container, world_rect),
2759 		 get_cmp_point_y (container, world_rect),
2760 		 &ax,
2761 		 NULL);
2762 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_b->item);
2763 	eel_canvas_w2c
2764 		(EEL_CANVAS (container),
2765 		 get_cmp_point_x (container, world_rect),
2766 		 get_cmp_point_y (container, world_rect),
2767 		 &bx,
2768 		 NULL);
2769 	
2770 	if (ax < bx) {
2771 		return -1;
2772 	}
2773 	if (ax > bx) {
2774 		return +1;
2775 	}
2776 	return 0;
2777 }
2778 
2779 static int
2780 compare_icons_vertical (NautilusCanvasContainer *container,
2781 			  NautilusCanvasIcon *icon_a,
2782 			  NautilusCanvasIcon *icon_b)
2783 {
2784 	EelDRect world_rect;
2785 	int ay, by;
2786 
2787 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_a->item);
2788 	eel_canvas_w2c
2789 		(EEL_CANVAS (container),
2790 		 get_cmp_point_x (container, world_rect),
2791 		 get_cmp_point_y (container, world_rect),
2792 		 NULL,
2793 		 &ay);
2794 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_b->item);
2795 	eel_canvas_w2c
2796 		(EEL_CANVAS (container),
2797 		 get_cmp_point_x (container, world_rect),
2798 		 get_cmp_point_y (container, world_rect),
2799 		 NULL,
2800 		 &by);
2801 	
2802 	if (ay < by) {
2803 		return -1;
2804 	}
2805 	if (ay > by) {
2806 		return +1;
2807 	}
2808 	return 0;
2809 }
2810 
2811 static int
2812 compare_icons_horizontal_first (NautilusCanvasContainer *container,
2813 				  NautilusCanvasIcon *icon_a,
2814 				  NautilusCanvasIcon *icon_b)
2815 {
2816 	EelDRect world_rect;
2817 	int ax, ay, bx, by;
2818 
2819 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_a->item);
2820 	eel_canvas_w2c
2821 		(EEL_CANVAS (container),
2822 		 get_cmp_point_x (container, world_rect),
2823 		 get_cmp_point_y (container, world_rect),
2824 		 &ax,
2825 		 &ay);
2826 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_b->item);
2827 	eel_canvas_w2c
2828 		(EEL_CANVAS (container),
2829 		 get_cmp_point_x (container, world_rect),
2830 		 get_cmp_point_y (container, world_rect),
2831 		 &bx,
2832 		 &by);
2833 	
2834 	if (ax < bx) {
2835 		return -1;
2836 	}
2837 	if (ax > bx) {
2838 		return +1;
2839 	}
2840 	if (ay < by) {
2841 		return -1;
2842 	}
2843 	if (ay > by) {
2844 		return +1;
2845 	}
2846 	return compare_icons_by_uri (container, icon_a, icon_b);
2847 }
2848 
2849 static int
2850 compare_icons_vertical_first (NautilusCanvasContainer *container,
2851 				NautilusCanvasIcon *icon_a,
2852 				NautilusCanvasIcon *icon_b)
2853 {
2854 	EelDRect world_rect;
2855 	int ax, ay, bx, by;
2856 
2857 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_a->item);
2858 	eel_canvas_w2c
2859 		(EEL_CANVAS (container),
2860 		 get_cmp_point_x (container, world_rect),
2861 		 get_cmp_point_y (container, world_rect),
2862 		 &ax,
2863 		 &ay);
2864 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon_b->item);
2865 	eel_canvas_w2c
2866 		(EEL_CANVAS (container),
2867 		 get_cmp_point_x (container, world_rect),
2868 		 get_cmp_point_y (container, world_rect),
2869 		 &bx,
2870 		 &by);
2871 	
2872 	if (ay < by) {
2873 		return -1;
2874 	}
2875 	if (ay > by) {
2876 		return +1;
2877 	}
2878 	if (ax < bx) {
2879 		return -1;
2880 	}
2881 	if (ax > bx) {
2882 		return +1;
2883 	}
2884 	return compare_icons_by_uri (container, icon_a, icon_b);
2885 }
2886 
2887 static gboolean
2888 leftmost_in_top_row (NautilusCanvasContainer *container,
2889 		     NautilusCanvasIcon *start_icon,
2890 		     NautilusCanvasIcon *best_so_far,
2891 		     NautilusCanvasIcon *candidate,
2892 		     void *data)
2893 {
2894 	if (best_so_far == NULL) {
2895 		return TRUE;
2896 	}
2897 	return compare_icons_vertical_first (container, best_so_far, candidate) > 0;
2898 }
2899 
2900 static gboolean
2901 rightmost_in_top_row (NautilusCanvasContainer *container,
2902 		      NautilusCanvasIcon *start_icon,
2903 		      NautilusCanvasIcon *best_so_far,
2904 		      NautilusCanvasIcon *candidate,
2905 		      void *data)
2906 {
2907 	if (best_so_far == NULL) {
2908 		return TRUE;
2909 	}
2910 	return compare_icons_vertical (container, best_so_far, candidate) > 0;
2911 	return compare_icons_horizontal (container, best_so_far, candidate) < 0;
2912 }
2913 
2914 static gboolean
2915 rightmost_in_bottom_row (NautilusCanvasContainer *container,
2916 			 NautilusCanvasIcon *start_icon,
2917 			 NautilusCanvasIcon *best_so_far,
2918 			 NautilusCanvasIcon *candidate,
2919 			 void *data)
2920 {
2921 	if (best_so_far == NULL) {
2922 		return TRUE;
2923 	}
2924 	return compare_icons_vertical_first (container, best_so_far, candidate) < 0;
2925 }
2926 
2927 static int
2928 compare_with_start_row (NautilusCanvasContainer *container,
2929 			NautilusCanvasIcon *icon)
2930 {
2931 	EelCanvasItem *item;
2932 
2933 	item = EEL_CANVAS_ITEM (icon->item);
2934 	
2935 	if (container->details->arrow_key_start_y < item->y1) {
2936 		return -1;
2937 	}
2938 	if (container->details->arrow_key_start_y > item->y2) {
2939 		return +1;
2940 	}
2941 	return 0;
2942 }
2943 
2944 static int
2945 compare_with_start_column (NautilusCanvasContainer *container,
2946 			   NautilusCanvasIcon *icon)
2947 {
2948 	EelCanvasItem *item;
2949 
2950 	item = EEL_CANVAS_ITEM (icon->item);
2951 	
2952 	if (container->details->arrow_key_start_x < item->x1) {
2953 		return -1;
2954 	}
2955 	if (container->details->arrow_key_start_x > item->x2) {
2956 		return +1;
2957 	}
2958 	return 0;
2959 }
2960 
2961 static gboolean
2962 same_row_right_side_leftmost (NautilusCanvasContainer *container,
2963 			      NautilusCanvasIcon *start_icon,
2964 			      NautilusCanvasIcon *best_so_far,
2965 			      NautilusCanvasIcon *candidate,
2966 			      void *data)
2967 {
2968 	/* Candidates not on the start row do not qualify. */
2969 	if (compare_with_start_row (container, candidate) != 0) {
2970 		return FALSE;
2971 	}
2972 
2973 	/* Candidates that are farther right lose out. */
2974 	if (best_so_far != NULL) {
2975 		if (compare_icons_horizontal_first (container,
2976 						      best_so_far,
2977 						      candidate) < 0) {
2978 			return FALSE;
2979 		}
2980 	}
2981 
2982 	/* Candidate to the left of the start do not qualify. */
2983 	if (compare_icons_horizontal_first (container,
2984 					      candidate,
2985 					      start_icon) <= 0) {
2986 		return FALSE;
2987 	}
2988 
2989 	return TRUE;
2990 }
2991 
2992 static gboolean
2993 same_row_left_side_rightmost (NautilusCanvasContainer *container,
2994 			      NautilusCanvasIcon *start_icon,
2995 			      NautilusCanvasIcon *best_so_far,
2996 			      NautilusCanvasIcon *candidate,
2997 			      void *data)
2998 {
2999 	/* Candidates not on the start row do not qualify. */
3000 	if (compare_with_start_row (container, candidate) != 0) {
3001 		return FALSE;
3002 	}
3003 
3004 	/* Candidates that are farther left lose out. */
3005 	if (best_so_far != NULL) {
3006 		if (compare_icons_horizontal_first (container,
3007 						      best_so_far,
3008 						      candidate) > 0) {
3009 			return FALSE;
3010 		}
3011 	}
3012 
3013 	/* Candidate to the right of the start do not qualify. */
3014 	if (compare_icons_horizontal_first (container,
3015 					      candidate,
3016 					      start_icon) >= 0) {
3017 		return FALSE;
3018 	}
3019 
3020 	return TRUE;
3021 }
3022 
3023 static gboolean
3024 next_row_leftmost (NautilusCanvasContainer *container,
3025 		   NautilusCanvasIcon *start_icon,
3026 	           NautilusCanvasIcon *best_so_far,
3027 		   NautilusCanvasIcon *candidate,
3028 		   void *data)
3029 {
3030 	/* sort out icons that are not below the current row */
3031 	if (compare_with_start_row (container, candidate) >= 0) {
3032 		return FALSE;
3033 	}
3034 
3035 	if (best_so_far != NULL) {
3036 		if (compare_icons_vertical_first (container,
3037 						    best_so_far,
3038 						    candidate) > 0) {
3039 			/* candidate is above best choice, but below the current row */
3040 			return TRUE;
3041 		}
3042 
3043 		if (compare_icons_horizontal_first (container,
3044 						      best_so_far,
3045 						      candidate) > 0) {
3046 			return TRUE;
3047 		}
3048 	}
3049 
3050 	return best_so_far == NULL;
3051 }
3052 
3053 static gboolean
3054 next_row_rightmost (NautilusCanvasContainer *container,
3055 		    NautilusCanvasIcon *start_icon,
3056 		    NautilusCanvasIcon *best_so_far,
3057 		    NautilusCanvasIcon *candidate,
3058 		    void *data)
3059 {
3060 	/* sort out icons that are not below the current row */
3061 	if (compare_with_start_row (container, candidate) >= 0) {
3062 		return FALSE;
3063 	}
3064 
3065 	if (best_so_far != NULL) {
3066 		if (compare_icons_vertical_first (container,
3067 						    best_so_far,
3068 						    candidate) > 0) {
3069 			/* candidate is above best choice, but below the current row */
3070 			return TRUE;
3071 		}
3072 
3073 		if (compare_icons_horizontal_first (container,
3074 						      best_so_far,
3075 						      candidate) < 0) {
3076 			return TRUE;
3077 		}
3078 	}
3079 
3080 	return best_so_far == NULL;
3081 }
3082 
3083 static gboolean
3084 next_column_bottommost (NautilusCanvasContainer *container,
3085 			NautilusCanvasIcon *start_icon,
3086 			NautilusCanvasIcon *best_so_far,
3087 			NautilusCanvasIcon *candidate,
3088 			void *data)
3089 {
3090 	/* sort out icons that are not on the right of the current column */
3091 	if (compare_with_start_column (container, candidate) >= 0) {
3092 		return FALSE;
3093 	}
3094 
3095 	if (best_so_far != NULL) {
3096 		if (compare_icons_horizontal_first (container,
3097 						      best_so_far,
3098 						      candidate) > 0) {
3099 			/* candidate is above best choice, but below the current row */
3100 			return TRUE;
3101 		}
3102 
3103 		if (compare_icons_vertical_first (container,
3104 						    best_so_far,
3105 						    candidate) < 0) {
3106 			return TRUE;
3107 		}
3108 	}
3109 
3110 	return best_so_far == NULL;
3111 }
3112 
3113 static gboolean
3114 previous_row_rightmost (NautilusCanvasContainer *container,
3115 		        NautilusCanvasIcon *start_icon,
3116 			NautilusCanvasIcon *best_so_far,
3117 			NautilusCanvasIcon *candidate,
3118 			void *data)
3119 {
3120 	/* sort out icons that are not above the current row */
3121 	if (compare_with_start_row (container, candidate) <= 0) {
3122 		return FALSE;
3123 	}
3124 
3125 	if (best_so_far != NULL) {
3126 		if (compare_icons_vertical_first (container,
3127 						    best_so_far,
3128 						    candidate) < 0) {
3129 			/* candidate is below the best choice, but above the current row */
3130 			return TRUE;
3131 		}
3132 
3133 		if (compare_icons_horizontal_first (container,
3134 						      best_so_far,
3135 						      candidate) < 0) {
3136 			return TRUE;
3137 		}
3138 	}
3139 
3140 	return best_so_far == NULL;
3141 }
3142 
3143 static gboolean
3144 same_column_above_lowest (NautilusCanvasContainer *container,
3145 			  NautilusCanvasIcon *start_icon,
3146 			  NautilusCanvasIcon *best_so_far,
3147 			  NautilusCanvasIcon *candidate,
3148 			  void *data)
3149 {
3150 	/* Candidates not on the start column do not qualify. */
3151 	if (compare_with_start_column (container, candidate) != 0) {
3152 		return FALSE;
3153 	}
3154 
3155 	/* Candidates that are higher lose out. */
3156 	if (best_so_far != NULL) {
3157 		if (compare_icons_vertical_first (container,
3158 						    best_so_far,
3159 						    candidate) > 0) {
3160 			return FALSE;
3161 		}
3162 	}
3163 
3164 	/* Candidates below the start do not qualify. */
3165 	if (compare_icons_vertical_first (container,
3166 					    candidate,
3167 					    start_icon) >= 0) {
3168 		return FALSE;
3169 	}
3170 
3171 	return TRUE;
3172 }
3173 
3174 static gboolean
3175 same_column_below_highest (NautilusCanvasContainer *container,
3176 			   NautilusCanvasIcon *start_icon,
3177 			   NautilusCanvasIcon *best_so_far,
3178 			   NautilusCanvasIcon *candidate,
3179 			   void *data)
3180 {
3181 	/* Candidates not on the start column do not qualify. */
3182 	if (compare_with_start_column (container, candidate) != 0) {
3183 		return FALSE;
3184 	}
3185 
3186 	/* Candidates that are lower lose out. */
3187 	if (best_so_far != NULL) {
3188 		if (compare_icons_vertical_first (container,
3189 						    best_so_far,
3190 						    candidate) < 0) {
3191 			return FALSE;
3192 		}
3193 	}
3194 
3195 	/* Candidates above the start do not qualify. */
3196 	if (compare_icons_vertical_first (container,
3197 					    candidate,
3198 					    start_icon) <= 0) {
3199 		return FALSE;
3200 	}
3201 
3202 	return TRUE;
3203 }
3204 
3205 static gboolean
3206 previous_column_highest (NautilusCanvasContainer *container,
3207 			 NautilusCanvasIcon *start_icon,
3208 			 NautilusCanvasIcon *best_so_far,
3209 			 NautilusCanvasIcon *candidate,
3210 			 void *data)
3211 {
3212 	/* sort out icons that are not before the current column */
3213 	if (compare_with_start_column (container, candidate) <= 0) {
3214 		return FALSE;
3215 	}
3216 
3217 	if (best_so_far != NULL) {
3218 		if (compare_icons_horizontal (container,
3219 						best_so_far,
3220 						candidate) < 0) {
3221 			/* candidate is right of the best choice, but left of the current column */
3222 			return TRUE;
3223 		}
3224 
3225 		if (compare_icons_vertical (container,
3226 					      best_so_far,
3227 					      candidate) > 0) {
3228 			return TRUE;
3229 		}
3230 	}
3231 
3232 	return best_so_far == NULL;
3233 }
3234 
3235 
3236 static gboolean
3237 next_column_highest (NautilusCanvasContainer *container,
3238 		     NautilusCanvasIcon *start_icon,
3239 		     NautilusCanvasIcon *best_so_far,
3240 		     NautilusCanvasIcon *candidate,
3241 		     void *data)
3242 {
3243 	/* sort out icons that are not after the current column */
3244 	if (compare_with_start_column (container, candidate) >= 0) {
3245 		return FALSE;
3246 	}
3247 
3248 	if (best_so_far != NULL) {
3249 		if (compare_icons_horizontal_first (container,
3250 						      best_so_far,
3251 						      candidate) > 0) {
3252 			/* candidate is left of the best choice, but right of the current column */
3253 			return TRUE;
3254 		}
3255 
3256 		if (compare_icons_vertical_first (container,
3257 						    best_so_far,
3258 						    candidate) > 0) {
3259 			return TRUE;
3260 		}
3261 	}
3262 
3263 	return best_so_far == NULL;
3264 }
3265 
3266 static gboolean
3267 previous_column_lowest (NautilusCanvasContainer *container,
3268 		        NautilusCanvasIcon *start_icon,
3269 			NautilusCanvasIcon *best_so_far,
3270 			NautilusCanvasIcon *candidate,
3271 			void *data)
3272 {
3273 	/* sort out icons that are not before the current column */
3274 	if (compare_with_start_column (container, candidate) <= 0) {
3275 		return FALSE;
3276 	}
3277 
3278 	if (best_so_far != NULL) {
3279 		if (compare_icons_horizontal_first (container,
3280 						      best_so_far,
3281 						      candidate) < 0) {
3282 			/* candidate is right of the best choice, but left of the current column */
3283 			return TRUE;
3284 		}
3285 
3286 		if (compare_icons_vertical_first (container,
3287 						    best_so_far,
3288 						    candidate) < 0) {
3289 			return TRUE;
3290 		}
3291 	}
3292 
3293 	return best_so_far == NULL;
3294 }
3295 
3296 static gboolean
3297 last_column_lowest (NautilusCanvasContainer *container,
3298 		    NautilusCanvasIcon *start_icon,
3299 		    NautilusCanvasIcon *best_so_far,
3300 		    NautilusCanvasIcon *candidate,
3301 		    void *data)
3302 {
3303 	if (best_so_far == NULL) {
3304 		return TRUE;
3305 	}
3306 	return compare_icons_horizontal_first (container, best_so_far, candidate) < 0;
3307 }
3308 
3309 static gboolean
3310 closest_in_90_degrees (NautilusCanvasContainer *container,
3311 		       NautilusCanvasIcon *start_icon,
3312 		       NautilusCanvasIcon *best_so_far,
3313 		       NautilusCanvasIcon *candidate,
3314 		       void *data)
3315 {
3316 	EelDRect world_rect;
3317 	int x, y;
3318 	int dx, dy;
3319 	int dist;
3320 	int *best_dist;
3321 
3322 
3323 	world_rect = nautilus_canvas_item_get_icon_rectangle (candidate->item);
3324 	eel_canvas_w2c
3325 		(EEL_CANVAS (container),
3326 		 get_cmp_point_x (container, world_rect),
3327 		 get_cmp_point_y (container, world_rect),
3328 		 &x,
3329 		 &y);
3330 
3331 	dx = x - container->details->arrow_key_start_x;
3332 	dy = y - container->details->arrow_key_start_y;
3333 	
3334 	switch (container->details->arrow_key_direction) {
3335 	case GTK_DIR_UP:
3336 		if (dy > 0 ||
3337 		    ABS(dx) > ABS(dy)) {
3338 			return FALSE;
3339 		}
3340 		break;
3341 	case GTK_DIR_DOWN:
3342 		if (dy < 0 ||
3343 		    ABS(dx) > ABS(dy)) {
3344 			return FALSE;
3345 		}
3346 		break;
3347 	case GTK_DIR_LEFT:
3348 		if (dx > 0 ||
3349 		    ABS(dy) > ABS(dx)) {
3350 			return FALSE;
3351 		}
3352 		break;
3353 	case GTK_DIR_RIGHT:
3354 		if (dx < 0 ||
3355 		    ABS(dy) > ABS(dx)) {
3356 			return FALSE;
3357 		}
3358 		break;
3359 	default:
3360 		g_assert_not_reached();
3361 	}
3362 
3363 	dist = dx*dx + dy*dy;
3364 	best_dist = data;
3365 	
3366 	if (best_so_far == NULL) {
3367 		*best_dist = dist;
3368 		return TRUE;
3369 	}
3370 
3371 	if (dist < *best_dist) {
3372 		*best_dist = dist;
3373 		return TRUE;
3374 	}
3375 
3376 	return FALSE;
3377 }
3378 
3379 static EelDRect 
3380 get_rubberband (NautilusCanvasIcon *icon1,
3381 		NautilusCanvasIcon *icon2)
3382 {
3383 	EelDRect rect1;
3384 	EelDRect rect2;
3385 	EelDRect ret;
3386 
3387 	eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon1->item),
3388 				    &rect1.x0, &rect1.y0, 
3389 				    &rect1.x1, &rect1.y1);
3390 	eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon2->item),
3391 				    &rect2.x0, &rect2.y0, 
3392 				    &rect2.x1, &rect2.y1);
3393 
3394 	eel_drect_union (&ret, &rect1, &rect2);
3395 
3396 	return ret;
3397 }
3398 
3399 static void
3400 keyboard_move_to (NautilusCanvasContainer *container,
3401 		  NautilusCanvasIcon *icon,
3402 		  NautilusCanvasIcon *from,
3403 		  GdkEventKey *event)
3404 {
3405 	if (icon == NULL) {
3406 		return;
3407 	}
3408 
3409 	if (event != NULL &&
3410 	    (event->state & GDK_CONTROL_MASK) != 0 &&
3411 	    (event->state & GDK_SHIFT_MASK) == 0) {
3412 		/* Move the keyboard focus. Use Control modifier
3413 		 * rather than Alt to avoid Sawfish conflict.
3414 		 */
3415 		set_keyboard_focus (container, icon);
3416 		container->details->keyboard_rubberband_start = NULL;
3417 	} else if (event != NULL &&
3418 		   ((event->state & GDK_CONTROL_MASK) != 0 ||
3419 		    !container->details->auto_layout) &&
3420 		   (event->state & GDK_SHIFT_MASK) != 0) {
3421 		/* Do rubberband selection */		
3422 		EelDRect rect;
3423 
3424 		if (from && !container->details->keyboard_rubberband_start) {
3425 			set_keyboard_rubberband_start (container, from);
3426 		} 
3427 
3428 		set_keyboard_focus (container, icon);
3429 
3430 		if (icon && container->details->keyboard_rubberband_start) {
3431 			rect = get_rubberband (container->details->keyboard_rubberband_start,
3432 					       icon);
3433 			rubberband_select (container, NULL, &rect);
3434 		}
3435 	} else if (event != NULL &&
3436 		   (event->state & GDK_CONTROL_MASK) == 0 &&
3437 		   (event->state & GDK_SHIFT_MASK) != 0) {
3438 		/* Select range */
3439 		NautilusCanvasIcon *start_icon;
3440 
3441 		start_icon = container->details->range_selection_base_icon;
3442 		if (start_icon == NULL || !start_icon->is_selected) {
3443 			start_icon = icon;
3444 			container->details->range_selection_base_icon = icon;
3445 		} 
3446 
3447 		set_keyboard_focus (container, icon);
3448 
3449 		if (select_range (container, start_icon, icon, TRUE)) {
3450 			g_signal_emit (container,
3451 				       signals[SELECTION_CHANGED], 0);
3452 		}
3453 	} else {
3454 		/* Select icons and get rid of the special keyboard focus. */
3455 		clear_keyboard_focus (container);
3456 		clear_keyboard_rubberband_start (container);
3457 		
3458 		container->details->range_selection_base_icon = icon;
3459 		if (select_one_unselect_others (container, icon)) {
3460 			g_signal_emit (container,
3461 				       signals[SELECTION_CHANGED], 0);
3462 		}
3463 	}
3464 	schedule_keyboard_icon_reveal (container, icon);
3465 }
3466 
3467 static void
3468 keyboard_home (NautilusCanvasContainer *container,
3469 	       GdkEventKey *event)
3470 {
3471 	NautilusCanvasIcon *from;
3472 	NautilusCanvasIcon *to;
3473 	
3474 	/* Home selects the first canvas.
3475 	 * Control-Home sets the keyboard focus to the first canvas.
3476 	 */
3477 
3478 	from = find_best_selected_icon (container, NULL,
3479 					  rightmost_in_bottom_row, 
3480 					  NULL);
3481 	to = find_best_icon (container, NULL, leftmost_in_top_row, NULL);	
3482 
3483 	keyboard_move_to (container, to, from, event);
3484 }
3485 
3486 static void
3487 keyboard_end (NautilusCanvasContainer *container,
3488 	      GdkEventKey *event)
3489 {
3490 	NautilusCanvasIcon *to;
3491 	NautilusCanvasIcon *from;
3492 
3493 	/* End selects the last canvas.
3494 	 * Control-End sets the keyboard focus to the last canvas.
3495 	 */
3496 	from = find_best_selected_icon (container, NULL,
3497 					  leftmost_in_top_row, 
3498 					  NULL);
3499 	to = find_best_icon (container, NULL,
3500 			       nautilus_canvas_container_is_layout_vertical (container) ?
3501 			       last_column_lowest :
3502 			       rightmost_in_bottom_row,
3503 			       NULL);
3504 
3505 	keyboard_move_to (container, to, from, event);
3506 }
3507 
3508 static void
3509 record_arrow_key_start (NautilusCanvasContainer *container,
3510 			NautilusCanvasIcon *icon,
3511 			GtkDirectionType direction)
3512 {
3513 	EelDRect world_rect;
3514 
3515 	world_rect = nautilus_canvas_item_get_icon_rectangle (icon->item);
3516 	eel_canvas_w2c
3517 		(EEL_CANVAS (container),
3518 		 get_cmp_point_x (container, world_rect),
3519 		 get_cmp_point_y (container, world_rect),
3520 		 &container->details->arrow_key_start_x,
3521 		 &container->details->arrow_key_start_y);
3522 	container->details->arrow_key_direction = direction;
3523 }
3524 
3525 static void
3526 keyboard_arrow_key (NautilusCanvasContainer *container,
3527 		    GdkEventKey *event,
3528 		    GtkDirectionType direction,
3529 		    IsBetterCanvasFunction better_start,
3530 		    IsBetterCanvasFunction empty_start,
3531 		    IsBetterCanvasFunction better_destination,
3532 		    IsBetterCanvasFunction better_destination_fallback,
3533 		    IsBetterCanvasFunction better_destination_fallback_fallback,
3534 		    IsBetterCanvasFunction better_destination_manual)
3535 {
3536 	NautilusCanvasIcon *from;
3537 	NautilusCanvasIcon *to;
3538 	int data;
3539 
3540 	/* Chose the icon to start with.
3541 	 * If we have a keyboard focus, start with it.
3542 	 * Otherwise, use the single selected icon.
3543 	 * If there's multiple selection, use the icon farthest toward the end.
3544 	 */
3545 	
3546 	from = container->details->keyboard_focus;
3547 
3548 	if (from == NULL) {
3549 		if (has_multiple_selection (container)) {
3550 			if (all_selected (container)) {
3551 				from = find_best_selected_icon
3552 					(container, NULL,
3553 					 empty_start, NULL);
3554 			} else {
3555 				from = find_best_selected_icon
3556 					(container, NULL,
3557 					 better_start, NULL);
3558 			}
3559 		} else {
3560 			from = get_first_selected_icon (container);
3561 		}
3562 	}
3563 
3564 	/* If there's no icon, select the icon farthest toward the end.
3565 	 * If there is an icon, select the next icon based on the arrow direction.
3566 	 */
3567 	if (from == NULL) {
3568 		to = from = find_best_icon
3569 			(container, NULL,
3570 			 empty_start, NULL);
3571 	} else {
3572 		record_arrow_key_start (container, from, direction);
3573 		
3574 		to = find_best_icon
3575 			(container, from,
3576 			 container->details->auto_layout ? better_destination : better_destination_manual,
3577 			 &data);
3578 
3579 		/* Wrap around to next/previous row/column */
3580 		if (to == NULL &&
3581 		    better_destination_fallback != NULL) {
3582 			to = find_best_icon
3583 				(container, from,
3584 				 better_destination_fallback,
3585 				 &data);
3586 		}
3587 
3588 		/* With a layout like
3589 		 * 1 2 3
3590 		 * 4
3591 		 * (horizontal layout)
3592 		 *
3593 		 * or
3594 		 *
3595 		 * 1 4
3596 		 * 2
3597 		 * 3 
3598 		 * (vertical layout)
3599 		 *
3600 		 * * pressing down for any of 1,2,3 (horizontal layout)
3601 		 * * pressing right for any of 1,2,3 (vertical layout)
3602 		 *
3603 		 * Should select 4.
3604 		 */
3605 		if (to == NULL &&
3606 		    container->details->auto_layout &&
3607 		    better_destination_fallback_fallback != NULL) {
3608 			to = find_best_icon
3609 				(container, from,
3610 				 better_destination_fallback_fallback,
3611 				 &data);
3612 		}
3613 
3614 		if (to == NULL) { 
3615 			to = from;
3616 		}
3617 
3618 	}
3619 
3620 	keyboard_move_to (container, to, from, event);
3621 }
3622 
3623 static gboolean
3624 is_rectangle_selection_event (GdkEventKey *event)
3625 {
3626 	return (event->state & GDK_CONTROL_MASK) != 0 &&
3627 		(event->state & GDK_SHIFT_MASK) != 0;
3628 }
3629 
3630 static void
3631 keyboard_right (NautilusCanvasContainer *container,
3632 		GdkEventKey *event)
3633 {
3634 	IsBetterCanvasFunction fallback;
3635 	IsBetterCanvasFunction next_column_fallback;
3636 
3637 	fallback = NULL;
3638 	if (container->details->auto_layout &&
3639 	    !nautilus_canvas_container_is_layout_vertical (container) &&
3640 	    !is_rectangle_selection_event (event)) {
3641 		fallback = next_row_leftmost;
3642 	}
3643 
3644 	next_column_fallback = NULL;
3645 	if (nautilus_canvas_container_is_layout_vertical (container) &&
3646 	    gtk_widget_get_direction (GTK_WIDGET (container)) != GTK_TEXT_DIR_RTL) {
3647 		next_column_fallback = next_column_bottommost;
3648 	}
3649 
3650 	/* Right selects the next icon in the same row.
3651 	 * Control-Right sets the keyboard focus to the next icon in the same row.
3652 	 */
3653 	keyboard_arrow_key (container,
3654 			    event,
3655 			    GTK_DIR_RIGHT,
3656 			    rightmost_in_bottom_row,
3657 			    nautilus_canvas_container_is_layout_rtl (container) ?
3658 			    rightmost_in_top_row : leftmost_in_top_row,
3659 			    same_row_right_side_leftmost,
3660 			    fallback,
3661 			    next_column_fallback,
3662 			    closest_in_90_degrees);
3663 }
3664 
3665 static void
3666 keyboard_left (NautilusCanvasContainer *container,
3667 	       GdkEventKey *event)
3668 {
3669 	IsBetterCanvasFunction fallback;
3670 	IsBetterCanvasFunction previous_column_fallback;
3671 
3672 	fallback = NULL;
3673 	if (container->details->auto_layout &&
3674 	    !nautilus_canvas_container_is_layout_vertical (container) &&
3675 	    !is_rectangle_selection_event (event)) {
3676 		fallback = previous_row_rightmost;
3677 	}
3678 
3679 	previous_column_fallback = NULL;
3680 	if (nautilus_canvas_container_is_layout_vertical (container) &&
3681 	    gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3682 		previous_column_fallback = previous_column_lowest;
3683 	}
3684 
3685 	/* Left selects the next icon in the same row.
3686 	 * Control-Left sets the keyboard focus to the next icon in the same row.
3687 	 */
3688 	keyboard_arrow_key (container,
3689 			    event,
3690 			    GTK_DIR_LEFT,
3691 			    rightmost_in_bottom_row,
3692 			    nautilus_canvas_container_is_layout_rtl (container) ?
3693 			    rightmost_in_top_row : leftmost_in_top_row,
3694 			    same_row_left_side_rightmost,
3695 			    fallback,
3696 			    previous_column_fallback,
3697 			    closest_in_90_degrees);
3698 }
3699 
3700 static void
3701 keyboard_down (NautilusCanvasContainer *container,
3702 	       GdkEventKey *event)
3703 {
3704 	IsBetterCanvasFunction fallback;
3705 	IsBetterCanvasFunction next_row_fallback;
3706 
3707 	fallback = NULL;
3708 	if (container->details->auto_layout &&
3709 	    nautilus_canvas_container_is_layout_vertical (container) &&
3710 	    !is_rectangle_selection_event (event)) {
3711 		if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3712 			fallback = previous_column_highest;
3713 		} else {
3714 			fallback = next_column_highest;
3715 		}
3716 	}
3717 
3718 	next_row_fallback = NULL;
3719 	if (!nautilus_canvas_container_is_layout_vertical (container)) {
3720 		if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3721 			next_row_fallback = next_row_leftmost;
3722 		} else {
3723 			next_row_fallback = next_row_rightmost;
3724 		}
3725 	}
3726 
3727 	/* Down selects the next icon in the same column.
3728 	 * Control-Down sets the keyboard focus to the next icon in the same column.
3729 	 */
3730 	keyboard_arrow_key (container,
3731 			    event,
3732 			    GTK_DIR_DOWN,
3733 			    rightmost_in_bottom_row,
3734 			    nautilus_canvas_container_is_layout_rtl (container) ?
3735 			    rightmost_in_top_row : leftmost_in_top_row,
3736 			    same_column_below_highest,
3737 			    fallback,
3738 			    next_row_fallback,
3739 			    closest_in_90_degrees);
3740 }
3741 
3742 static void
3743 keyboard_up (NautilusCanvasContainer *container,
3744 	     GdkEventKey *event)
3745 {
3746 	IsBetterCanvasFunction fallback;
3747 
3748 	fallback = NULL;
3749 	if (container->details->auto_layout &&
3750 	    nautilus_canvas_container_is_layout_vertical (container) &&
3751 	    !is_rectangle_selection_event (event)) {
3752 		if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL) {
3753 			fallback = next_column_bottommost;
3754 		} else {
3755 			fallback = previous_column_lowest;
3756 		}
3757 	}
3758 
3759 	/* Up selects the next icon in the same column.
3760 	 * Control-Up sets the keyboard focus to the next icon in the same column.
3761 	 */
3762 	keyboard_arrow_key (container,
3763 			    event,
3764 			    GTK_DIR_UP,
3765 			    rightmost_in_bottom_row,
3766 			    nautilus_canvas_container_is_layout_rtl (container) ?
3767 			    rightmost_in_top_row : leftmost_in_top_row,
3768 			    same_column_above_lowest,
3769 			    fallback,
3770 			    NULL,
3771 			    closest_in_90_degrees);
3772 }
3773 
3774 static void
3775 keyboard_space (NautilusCanvasContainer *container,
3776 		GdkEventKey *event)
3777 {
3778 	NautilusCanvasIcon *icon;
3779 	
3780 	if (!has_selection (container) &&
3781 	    container->details->keyboard_focus != NULL) {
3782 		keyboard_move_to (container,
3783 				  container->details->keyboard_focus,
3784 				  NULL, NULL);
3785 	} else if ((event->state & GDK_CONTROL_MASK) != 0 &&
3786 		   (event->state & GDK_SHIFT_MASK) == 0) {
3787 		/* Control-space toggles the selection state of the current icon. */
3788 		if (container->details->keyboard_focus != NULL) {
3789 			icon_toggle_selected (container, container->details->keyboard_focus);
3790 			g_signal_emit (container, signals[SELECTION_CHANGED], 0);
3791 			if  (container->details->keyboard_focus->is_selected) {
3792 				container->details->range_selection_base_icon = container->details->keyboard_focus;
3793 			} 
3794 		} else {
3795 			icon = find_best_selected_icon (container,
3796 							    NULL,
3797 							    leftmost_in_top_row,
3798 							    NULL);
3799 			if (icon == NULL) {
3800 				icon = find_best_icon (container,
3801 							   NULL,
3802 							   leftmost_in_top_row,
3803 							   NULL);
3804 			}
3805 			if (icon != NULL) {
3806 				set_keyboard_focus (container, icon);
3807 			}
3808 		}
3809 	} else if ((event->state & GDK_SHIFT_MASK) != 0) {
3810 		activate_selected_items_alternate (container, NULL);
3811 	} else {
3812 		preview_selected_items (container);
3813 	}
3814 }
3815 
3816 /* look for the first canvas that matches the longest part of a given
3817  * search pattern
3818  */
3819 typedef struct {
3820 	gunichar *name;
3821 	int last_match_length;
3822 } BestNameMatch;
3823 
3824 #ifndef TAB_NAVIGATION_DISABLED
3825 static void
3826 select_previous_or_next_icon (NautilusCanvasContainer *container, 
3827 				gboolean next, 
3828 				GdkEventKey *event)
3829 {
3830 	NautilusCanvasIcon *icon;
3831 	const GList *item;
3832 
3833 	item = NULL;
3834 	/* Chose the icon to start with.
3835 	 * If we have a keyboard focus, start with it.
3836 	 * Otherwise, use the single selected icon.
3837 	 */
3838 	icon = container->details->keyboard_focus;
3839 	if (icon == NULL) {
3840 		icon = get_first_selected_icon (container);
3841 	}
3842 
3843 	if (icon != NULL) {
3844 		/* must have at least @canvas in the list */
3845 		g_assert (container->details->icons != NULL);
3846 		item = g_list_find (container->details->icons, icon);
3847 		g_assert (item != NULL);
3848 		
3849 		item = next ? item->next : item->prev;
3850 		if (item == NULL) {
3851 			item = next ? g_list_first (container->details->icons) : g_list_last (container->details->icons);
3852 		}
3853 
3854 	} else if (container->details->icons != NULL) {
3855 		/* no selection yet, pick the first or last item to select */
3856 		item = next ? g_list_first (container->details->icons) : g_list_last (container->details->icons);
3857 	}
3858 
3859 	icon = (item != NULL) ? item->data : NULL;
3860 
3861 	if (icon != NULL) {
3862 		keyboard_move_to (container, icon, NULL, event);
3863 	}
3864 }
3865 #endif
3866 
3867 static void
3868 destroy (GtkWidget *object)
3869 {
3870 	NautilusCanvasContainer *container;
3871 
3872 	container = NAUTILUS_CANVAS_CONTAINER (object);
3873 
3874         nautilus_canvas_container_clear (container);
3875 
3876 	if (container->details->rubberband_info.timer_id != 0) {
3877 		g_source_remove (container->details->rubberband_info.timer_id);
3878 		container->details->rubberband_info.timer_id = 0;
3879 	}
3880 
3881         if (container->details->idle_id != 0) {
3882 		g_source_remove (container->details->idle_id);
3883 		container->details->idle_id = 0;
3884 	}
3885 
3886 	if (container->details->stretch_idle_id != 0) {
3887 		g_source_remove (container->details->stretch_idle_id);
3888 		container->details->stretch_idle_id = 0;
3889 	}
3890 
3891         if (container->details->align_idle_id != 0) {
3892 		g_source_remove (container->details->align_idle_id);
3893 		container->details->align_idle_id = 0;
3894 	}
3895 
3896         if (container->details->selection_changed_id != 0) {
3897 		g_source_remove (container->details->selection_changed_id);
3898 		container->details->selection_changed_id = 0;
3899 	}
3900 
3901         if (container->details->size_allocation_count_id != 0) {
3902 		g_source_remove (container->details->size_allocation_count_id);
3903 		container->details->size_allocation_count_id = 0;
3904 	}
3905 
3906 	GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->destroy (object);
3907 }
3908 
3909 static void
3910 finalize (GObject *object)
3911 {
3912 	NautilusCanvasContainerDetails *details;
3913 
3914 	details = NAUTILUS_CANVAS_CONTAINER (object)->details;
3915 
3916 	g_signal_handlers_disconnect_by_func (nautilus_icon_view_preferences,
3917 					      text_ellipsis_limit_changed_container_callback,
3918 					      object);
3919 	g_signal_handlers_disconnect_by_func (nautilus_desktop_preferences,
3920 					      text_ellipsis_limit_changed_container_callback,
3921 					      object);
3922 
3923 	g_hash_table_destroy (details->icon_set);
3924 	details->icon_set = NULL;
3925 
3926 	g_free (details->font);
3927 
3928 	if (details->a11y_item_action_queue != NULL) {
3929 		while (!g_queue_is_empty (details->a11y_item_action_queue)) {
3930 			g_free (g_queue_pop_head (details->a11y_item_action_queue));
3931 		}
3932 		g_queue_free (details->a11y_item_action_queue);
3933 	}
3934 	if (details->a11y_item_action_idle_handler != 0) {
3935 		g_source_remove (details->a11y_item_action_idle_handler);
3936 	}
3937 
3938 	g_free (details);
3939 
3940 	G_OBJECT_CLASS (nautilus_canvas_container_parent_class)->finalize (object);
3941 }
3942 
3943 /* GtkWidget methods.  */
3944 
3945 static gboolean
3946 clear_size_allocation_count (gpointer data)
3947 {
3948 	NautilusCanvasContainer *container;
3949 
3950 	container = NAUTILUS_CANVAS_CONTAINER (data);
3951 
3952 	container->details->size_allocation_count_id = 0;
3953 	container->details->size_allocation_count = 0;
3954 
3955 	return FALSE;
3956 }
3957 
3958 static void
3959 size_allocate (GtkWidget *widget,
3960 	       GtkAllocation *allocation)
3961 {
3962 	NautilusCanvasContainer *container;
3963 	gboolean need_layout_redone;
3964 	GtkAllocation wid_allocation;
3965 
3966 	container = NAUTILUS_CANVAS_CONTAINER (widget);
3967 
3968 	need_layout_redone = !container->details->has_been_allocated;
3969 	gtk_widget_get_allocation (widget, &wid_allocation);
3970 
3971 	if (allocation->width != wid_allocation.width) {
3972 		need_layout_redone = TRUE;
3973 	}
3974 
3975 	if (allocation->height != wid_allocation.height) {
3976 		need_layout_redone = TRUE;
3977 	}
3978 
3979 	/* Under some conditions we can end up in a loop when size allocating.
3980 	 * This happens when the icons don't fit without a scrollbar, but fits
3981 	 * when a scrollbar is added (bug #129963 for details).
3982 	 * We keep track of this looping by increasing a counter in size_allocate
3983 	 * and clearing it in a high-prio idle (the only way to detect the loop is
3984 	 * done).
3985 	 * When we've done at more than two iterations (with/without scrollbar)
3986 	 * we terminate this looping by not redoing the layout when the width
3987 	 * is wider than the current one (i.e when removing the scrollbar).
3988 	 */
3989 	if (container->details->size_allocation_count_id == 0) {
3990 		container->details->size_allocation_count_id = 
3991 			g_idle_add_full  (G_PRIORITY_HIGH,
3992 					  clear_size_allocation_count,
3993 					  container, NULL);
3994 	}
3995 	container->details->size_allocation_count++;
3996 	if (container->details->size_allocation_count > 2 &&
3997 	    allocation->width >= wid_allocation.width) {
3998 		need_layout_redone = FALSE;
3999 	}
4000 	
4001 	GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->size_allocate (widget, allocation);
4002 
4003 	container->details->has_been_allocated = TRUE;
4004 
4005 	if (need_layout_redone) {
4006 		redo_layout (container);
4007 	}
4008 }
4009 
4010 static GtkSizeRequestMode
4011 get_request_mode (GtkWidget *widget)
4012 {
4013 	/* Don't trade size at all, since we get whatever we get anyway. */
4014 	return GTK_SIZE_REQUEST_CONSTANT_SIZE;
4015 }
4016 
4017 /* We need to implement these since the GtkScrolledWindow uses them
4018    to guess whether to show scrollbars or not, and if we don't report
4019    anything it'll tend to get it wrong causing double calls
4020    to size_allocate (at different sizes) during its size allocation. */
4021 static void
4022 get_prefered_width (GtkWidget *widget,
4023 		    gint      *minimum_size,
4024 		    gint      *natural_size)
4025 {
4026 	EelCanvasGroup *root;
4027 	double x1, x2;
4028 	int cx1, cx2;
4029 	int width;
4030 
4031 	root = eel_canvas_root (EEL_CANVAS (widget));
4032 	eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (root),
4033 				    &x1, NULL, &x2, NULL);
4034 	eel_canvas_w2c (EEL_CANVAS (widget), x1, 0, &cx1, NULL);
4035 	eel_canvas_w2c (EEL_CANVAS (widget), x2, 0, &cx2, NULL);
4036 
4037 	width = cx2 - cx1;
4038 	if (natural_size) {
4039 		*natural_size = width;
4040 	}
4041 	if (minimum_size) {
4042 		*minimum_size = width;
4043 	}
4044 }
4045 
4046 static void
4047 get_prefered_height (GtkWidget *widget,
4048 		     gint      *minimum_size,
4049 		     gint      *natural_size)
4050 {
4051 	EelCanvasGroup *root;
4052 	double y1, y2;
4053 	int cy1, cy2;
4054 	int height;
4055 
4056 	root = eel_canvas_root (EEL_CANVAS (widget));
4057 	eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (root),
4058 				    NULL, &y1, NULL, &y2);
4059 	eel_canvas_w2c (EEL_CANVAS (widget), 0, y1, NULL, &cy1);
4060 	eel_canvas_w2c (EEL_CANVAS (widget), 0, y2, NULL, &cy2);
4061 
4062 	height = cy2 - cy1;
4063 	if (natural_size) {
4064 		*natural_size = height;
4065 	}
4066 	if (minimum_size) {
4067 		*minimum_size = height;
4068 	}
4069 }
4070 
4071 static void
4072 realize (GtkWidget *widget)
4073 {
4074 	GtkAdjustment *vadj, *hadj;
4075 	NautilusCanvasContainer *container;
4076 
4077 	GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->realize (widget);
4078 
4079 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4080 
4081 	/* Ensure that the desktop window is native so the background
4082 	   set on it is drawn by X. */
4083 	if (container->details->is_desktop) {
4084 		gdk_x11_window_get_xid (gtk_layout_get_bin_window (GTK_LAYOUT (widget)));
4085 	}
4086 
4087 	/* Set up DnD.  */
4088 	nautilus_canvas_dnd_init (container);
4089 
4090 	hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (widget));
4091 	g_signal_connect (hadj, "value_changed",
4092 			  G_CALLBACK (handle_hadjustment_changed), widget);
4093 
4094 	vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (widget));
4095 	g_signal_connect (vadj, "value_changed",
4096 			  G_CALLBACK (handle_vadjustment_changed), widget);
4097 
4098 }
4099 
4100 static void
4101 unrealize (GtkWidget *widget)
4102 {
4103 	NautilusCanvasContainer *container;
4104 
4105 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4106 
4107 	nautilus_canvas_dnd_fini (container);
4108 
4109 	GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->unrealize (widget);
4110 }
4111 
4112 static void
4113 style_updated (GtkWidget *widget)
4114 {
4115 	NautilusCanvasContainer *container;
4116 
4117 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4118 	container->details->use_drop_shadows = container->details->drop_shadows_requested;
4119 
4120 	/* Don't chain up to parent, if this is a desktop container,
4121 	 * because that resets the background of the window.
4122 	 */
4123 	if (!nautilus_canvas_container_get_is_desktop (container)) {
4124 		GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->style_updated (widget);
4125 	}
4126 
4127 	if (gtk_widget_get_realized (widget)) {
4128 		invalidate_labels (container);
4129 		nautilus_canvas_container_request_update_all (container);
4130 	}
4131 }
4132 
4133 static gboolean
4134 button_press_event (GtkWidget *widget,
4135 		    GdkEventButton *event)
4136 {
4137 	NautilusCanvasContainer *container;
4138 	gboolean selection_changed;
4139 	gboolean return_value;
4140 	gboolean clicked_on_icon;
4141 
4142 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4143         container->details->button_down_time = event->time;
4144 	
4145         /* Forget about the old keyboard selection now that we've started mousing. */
4146         clear_keyboard_focus (container);
4147 	clear_keyboard_rubberband_start (container);
4148 
4149 	if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
4150 		/* We use our own double-click detection. */
4151 		return TRUE;
4152 	}
4153 
4154 	/* Invoke the canvas event handler and see if an item picks up the event. */
4155 	clicked_on_icon = GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->button_press_event (widget, event);
4156 	
4157 	/* Move focus to canvas container, unless we're still renaming (to avoid exiting
4158 	 * renaming mode)
4159 	 */
4160   	if (!gtk_widget_has_focus (widget) && !(is_renaming (container) || is_renaming_pending (container))) {
4161     		gtk_widget_grab_focus (widget);
4162     	}
4163 
4164 	if (clicked_on_icon) {
4165 		return TRUE;
4166 	}
4167 
4168 	if (event->button == DRAG_BUTTON &&
4169 	    event->type == GDK_BUTTON_PRESS) {
4170 		/* Clear the last click icon for double click */
4171 		container->details->double_click_icon[1] = container->details->double_click_icon[0];
4172 		container->details->double_click_icon[0] = NULL;
4173 	}
4174 	
4175 	/* Button 1 does rubber banding. */
4176 	if (event->button == RUBBERBAND_BUTTON) {
4177 		if (! button_event_modifies_selection (event)) {
4178 			selection_changed = unselect_all (container);
4179 			if (selection_changed) {
4180 				g_signal_emit (container,
4181 					       signals[SELECTION_CHANGED], 0);
4182 			}
4183 		}
4184 
4185 		start_rubberbanding (container, event);
4186 		return TRUE;
4187 	}
4188 
4189 	/* Prevent multi-button weirdness such as bug 6181 */
4190 	if (container->details->rubberband_info.active) {
4191 		return TRUE;
4192 	}
4193 	
4194 	/* Button 2 may be passed to the window manager. */
4195 	if (event->button == MIDDLE_BUTTON) {
4196 		selection_changed = unselect_all (container);
4197 		if (selection_changed) {
4198 			g_signal_emit (container, signals[SELECTION_CHANGED], 0);
4199 		}
4200 		g_signal_emit (widget, signals[MIDDLE_CLICK], 0, event);
4201 		return TRUE;
4202 	}
4203 
4204 	/* Button 3 does a contextual menu. */
4205 	if (event->button == CONTEXTUAL_MENU_BUTTON) {
4206 		end_renaming_mode (container, TRUE);
4207 		selection_changed = unselect_all (container);
4208 		if (selection_changed) {
4209 			g_signal_emit (container, signals[SELECTION_CHANGED], 0);
4210 		}
4211 		g_signal_emit (widget, signals[CONTEXT_CLICK_BACKGROUND], 0, event);
4212 		return TRUE;
4213 	}
4214 	
4215 	/* Otherwise, we emit a button_press message. */
4216 	g_signal_emit (widget,
4217 		       signals[BUTTON_PRESS], 0, event,
4218 		       &return_value);
4219 	return return_value;
4220 }
4221 
4222 static void
4223 nautilus_canvas_container_did_not_drag (NautilusCanvasContainer *container,
4224 					GdkEventButton *event)
4225 {
4226 	NautilusCanvasContainerDetails *details;
4227 	gboolean selection_changed;
4228 	static gint64 last_click_time = 0;
4229 	static gint click_count = 0;
4230 	gint double_click_time;
4231 	gint64 current_time;
4232 		
4233 	details = container->details;
4234 
4235 	if (details->icon_selected_on_button_down &&
4236 	    ((event->state & GDK_CONTROL_MASK) != 0 ||
4237 	     (event->state & GDK_SHIFT_MASK) == 0)) {
4238 		if (button_event_modifies_selection (event)) {
4239 			details->range_selection_base_icon = NULL;
4240 			icon_toggle_selected (container, details->drag_icon);
4241 			g_signal_emit (container,
4242 				       signals[SELECTION_CHANGED], 0);
4243 		} else {
4244 			details->range_selection_base_icon = details->drag_icon;
4245 			selection_changed = select_one_unselect_others 
4246 				(container, details->drag_icon);
4247 			
4248 			if (selection_changed) {
4249 				g_signal_emit (container,
4250 					       signals[SELECTION_CHANGED], 0);
4251 			}
4252 		}
4253 	} 
4254 	
4255 	if (details->drag_icon != NULL &&
4256 	    (details->single_click_mode ||
4257 	     event->button == MIDDLE_BUTTON)) {
4258 		/* Determine click count */
4259 		g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))), 
4260 			      "gtk-double-click-time", &double_click_time,
4261 			      NULL);
4262 		current_time = g_get_monotonic_time ();
4263 		if (current_time - last_click_time < double_click_time * 1000) {
4264 			click_count++;
4265 		} else {
4266 			click_count = 0;
4267 		}
4268 		
4269 		/* Stash time for next compare */
4270 		last_click_time = current_time;
4271 
4272 		/* If single-click mode, activate the selected icons, unless modifying
4273 		 * the selection or pressing for a very long time, or double clicking.
4274 		 */
4275 
4276 		
4277 		if (click_count == 0 &&
4278 		    event->time - details->button_down_time < MAX_CLICK_TIME &&
4279 		    ! button_event_modifies_selection (event)) {
4280 			
4281 			/* It's a tricky UI issue whether this should activate
4282 			 * just the clicked item (as if it were a link), or all
4283 			 * the selected items (as if you were issuing an "activate
4284 			 * selection" command). For now, we're trying the activate
4285 			 * entire selection version to see how it feels. Note that
4286 			 * NautilusList goes the other way because its "links" seem
4287 			 * much more link-like.
4288 			 */
4289 			if (event->button == MIDDLE_BUTTON) {
4290 				activate_selected_items_alternate (container, NULL);
4291 			} else {
4292 				activate_selected_items (container);
4293 			}
4294 		}
4295 	}
4296 }
4297 
4298 static gboolean
4299 clicked_within_double_click_interval (NautilusCanvasContainer *container)
4300 {
4301 	static gint64 last_click_time = 0;
4302 	static gint click_count = 0;
4303 	gint double_click_time;
4304 	gint64 current_time;
4305 
4306 	/* Determine click count */
4307 	g_object_get (G_OBJECT (gtk_widget_get_settings (GTK_WIDGET (container))), 
4308 		      "gtk-double-click-time", &double_click_time,
4309 		      NULL);
4310 	current_time = g_get_monotonic_time ();
4311 	if (current_time - last_click_time < double_click_time * 1000) {
4312 		click_count++;
4313 	} else {
4314 		click_count = 0;
4315 	}
4316 
4317 	/* Stash time for next compare */
4318 	last_click_time = current_time;
4319 
4320 	/* Only allow double click */
4321 	if (click_count == 1) {
4322 		click_count = 0;
4323 		return TRUE;
4324 	} else {
4325 		return FALSE;
4326 	}
4327 }
4328 
4329 static void
4330 clear_drag_state (NautilusCanvasContainer *container)
4331 {
4332 	container->details->drag_icon = NULL;
4333 	container->details->drag_state = DRAG_STATE_INITIAL;
4334 }
4335 
4336 static gboolean
4337 start_stretching (NautilusCanvasContainer *container)
4338 {
4339 	NautilusCanvasContainerDetails *details;
4340 	NautilusCanvasIcon *icon;
4341 	GtkWidget *toplevel;
4342 	GtkCornerType corner;
4343 	GdkCursor *cursor;
4344 
4345 	details = container->details;
4346 	icon = details->stretch_icon;
4347 	
4348 	/* Check if we hit the stretch handles. */
4349 	if (!nautilus_canvas_item_hit_test_stretch_handles (icon->item,
4350 								   details->drag_x, details->drag_y,
4351 								   &corner)) {
4352 		return FALSE;
4353 	}
4354 
4355 	switch (corner) {
4356 	case GTK_CORNER_TOP_LEFT:
4357 		cursor = gdk_cursor_new (GDK_TOP_LEFT_CORNER);
4358 		break;
4359 	case GTK_CORNER_BOTTOM_LEFT:
4360 		cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER);
4361 		break;
4362 	case GTK_CORNER_TOP_RIGHT:
4363 		cursor = gdk_cursor_new (GDK_TOP_RIGHT_CORNER);
4364 		break;
4365 	case GTK_CORNER_BOTTOM_RIGHT:
4366 		cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
4367 		break;
4368 	default: 
4369 		cursor = NULL;
4370 		break;
4371 	}
4372 	/* Set up the dragging. */
4373 	details->drag_state = DRAG_STATE_STRETCH;
4374 	eel_canvas_w2c (EEL_CANVAS (container),
4375 			details->drag_x,
4376 			details->drag_y,
4377 			&details->stretch_start.pointer_x,
4378 			&details->stretch_start.pointer_y);
4379 	eel_canvas_w2c (EEL_CANVAS (container),
4380 			icon->x, icon->y,
4381 			&details->stretch_start.icon_x,
4382 			&details->stretch_start.icon_y);
4383 	icon_get_size (container, icon,
4384 			 &details->stretch_start.icon_size);
4385 
4386 	eel_canvas_item_grab (EEL_CANVAS_ITEM (icon->item),
4387 			      (GDK_POINTER_MOTION_MASK
4388 			       | GDK_BUTTON_RELEASE_MASK),
4389 			      cursor,
4390 			      GDK_CURRENT_TIME);
4391 	if (cursor)
4392 		g_object_unref (cursor);
4393 
4394 	/* Ensure the window itself is focused.. */
4395 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
4396 	if (toplevel != NULL && gtk_widget_get_realized (toplevel)) {
4397 		gdk_window_focus (gtk_widget_get_window (toplevel), GDK_CURRENT_TIME);
4398 	}
4399 
4400 	return TRUE;
4401 }
4402 
4403 static gboolean
4404 update_stretch_at_idle (NautilusCanvasContainer *container)
4405 {
4406 	NautilusCanvasContainerDetails *details;
4407 	NautilusCanvasIcon *icon;
4408 	double world_x, world_y;
4409 	StretchState stretch_state;
4410 
4411 	details = container->details;
4412 	icon = details->stretch_icon;
4413 
4414 	if (icon == NULL) {
4415 		container->details->stretch_idle_id = 0;
4416 		return FALSE;
4417 	}
4418 
4419 	eel_canvas_w2c (EEL_CANVAS (container),
4420 			details->world_x, details->world_y,
4421 			&stretch_state.pointer_x, &stretch_state.pointer_y);
4422 
4423 	compute_stretch (&details->stretch_start,
4424 			 &stretch_state);
4425 
4426 	eel_canvas_c2w (EEL_CANVAS (container),
4427 			stretch_state.icon_x, stretch_state.icon_y,
4428 			&world_x, &world_y);
4429 
4430 	icon_set_position (icon, world_x, world_y);
4431 	icon_set_size (container, icon, stretch_state.icon_size, FALSE, FALSE);
4432 
4433 	container->details->stretch_idle_id = 0;
4434 
4435 	return FALSE;
4436 }	
4437 
4438 static void
4439 continue_stretching (NautilusCanvasContainer *container,
4440 		     double world_x, double world_y)
4441 {
4442 
4443 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
4444 
4445 	container->details->world_x = world_x;
4446 	container->details->world_y = world_y;
4447 
4448 	if (container->details->stretch_idle_id == 0) {		
4449 		container->details->stretch_idle_id = g_idle_add ((GSourceFunc) update_stretch_at_idle, container);
4450 	}
4451 }
4452 
4453 static gboolean
4454 keyboard_stretching (NautilusCanvasContainer *container,
4455 		     GdkEventKey           *event)
4456 {
4457 	NautilusCanvasIcon *icon;
4458 	guint size;
4459 
4460 	icon = container->details->stretch_icon;
4461 
4462 	if (icon == NULL || !icon->is_selected) {
4463 		return FALSE;
4464 	}
4465 
4466 	icon_get_size (container, icon, &size);
4467 
4468 	switch (event->keyval) {
4469 	case GDK_KEY_equal:
4470 	case GDK_KEY_plus:
4471 	case GDK_KEY_KP_Add:
4472 		icon_set_size (container, icon, size + 5, FALSE, FALSE);
4473 		break;
4474 	case GDK_KEY_minus:
4475 	case GDK_KEY_KP_Subtract:
4476 		icon_set_size (container, icon, size - 5, FALSE, FALSE);
4477 		break;
4478 	case GDK_KEY_0:
4479 	case GDK_KEY_KP_0:
4480 		nautilus_canvas_container_move_icon (container, icon,
4481 						       icon->x, icon->y,
4482 						       1.0,
4483 						       FALSE, TRUE, TRUE);
4484 		break;
4485 	}
4486 	
4487 	return TRUE;
4488 }
4489 
4490 static void
4491 ungrab_stretch_icon (NautilusCanvasContainer *container)
4492 {
4493 	eel_canvas_item_ungrab (EEL_CANVAS_ITEM (container->details->stretch_icon->item),
4494 				GDK_CURRENT_TIME);
4495 }
4496 
4497 static void
4498 end_stretching (NautilusCanvasContainer *container,
4499 		double world_x, double world_y)
4500 {
4501 	NautilusCanvasPosition position;
4502 	NautilusCanvasIcon *icon;
4503 	
4504 	continue_stretching (container, world_x, world_y);
4505 	ungrab_stretch_icon (container);
4506 
4507 	/* now that we're done stretching, update the icon's position */
4508 	
4509 	icon = container->details->drag_icon;	
4510 	if (nautilus_canvas_container_is_layout_rtl (container)) {
4511 		position.x = icon->saved_ltr_x = get_mirror_x_position (container, icon, icon->x);
4512 	} else {
4513 		position.x = icon->x;
4514 	}
4515 	position.y = icon->y;
4516 	position.scale = icon->scale;
4517 	g_signal_emit (container,
4518 		       signals[ICON_POSITION_CHANGED], 0,
4519 		       icon->data, &position);
4520 	
4521 	clear_drag_state (container);
4522 	redo_layout (container);
4523 }
4524 
4525 static gboolean
4526 undo_stretching (NautilusCanvasContainer *container)
4527 {
4528 	NautilusCanvasIcon *stretched_icon;
4529 
4530 	stretched_icon = container->details->stretch_icon;
4531 
4532 	if (stretched_icon == NULL) {
4533 		return FALSE;
4534 	}
4535 
4536 	if (container->details->drag_state == DRAG_STATE_STRETCH) {
4537 		ungrab_stretch_icon (container);
4538 		clear_drag_state (container);
4539 	}
4540 	nautilus_canvas_item_set_show_stretch_handles
4541 		(stretched_icon->item, FALSE);
4542 	
4543 	icon_set_position (stretched_icon,
4544 			     container->details->stretch_initial_x,
4545 			     container->details->stretch_initial_y);
4546 	icon_set_size (container,
4547 			 stretched_icon, 
4548 			 container->details->stretch_initial_size,
4549 			 TRUE,
4550 			 TRUE);
4551 	
4552 	container->details->stretch_icon = NULL;				
4553 	emit_stretch_ended (container, stretched_icon);
4554 	redo_layout (container);
4555 
4556 	return TRUE;
4557 }
4558 
4559 static gboolean
4560 button_release_event (GtkWidget *widget,
4561 		      GdkEventButton *event)
4562 {
4563 	NautilusCanvasContainer *container;
4564 	NautilusCanvasContainerDetails *details;
4565 	double world_x, world_y;
4566 	
4567 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4568 	details = container->details;
4569 
4570 	if (event->button == RUBBERBAND_BUTTON && details->rubberband_info.active) {
4571 		stop_rubberbanding (container, event->time);
4572 		return TRUE;
4573 	}
4574 	
4575 	if (event->button == details->drag_button) {
4576 		details->drag_button = 0;
4577 
4578 		switch (details->drag_state) {
4579 		case DRAG_STATE_MOVE_OR_COPY:
4580 			if (!details->drag_started) {
4581 				nautilus_canvas_container_did_not_drag (container, event);
4582 			} else {
4583 				nautilus_canvas_dnd_end_drag (container);
4584 				DEBUG ("Ending drag from canvas container");
4585 			}
4586 			break;
4587 		case DRAG_STATE_STRETCH:
4588 			eel_canvas_window_to_world
4589 				(EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
4590 			end_stretching (container, world_x, world_y);
4591 			break;
4592 		default:
4593 			break;
4594 		}
4595 
4596 		clear_drag_state (container);
4597 		return TRUE;
4598 	}
4599 
4600 	return GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->button_release_event (widget, event);
4601 }
4602 
4603 static int
4604 motion_notify_event (GtkWidget *widget,
4605 		     GdkEventMotion *event)
4606 {
4607 	NautilusCanvasContainer *container;
4608 	NautilusCanvasContainerDetails *details;
4609 	double world_x, world_y;
4610 	int canvas_x, canvas_y;
4611 	GdkDragAction actions;
4612 
4613 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4614 	details = container->details;
4615 
4616 	if (details->drag_button != 0) {
4617 		switch (details->drag_state) {
4618 		case DRAG_STATE_MOVE_OR_COPY:
4619 			if (details->drag_started) {
4620 				break;
4621 			}
4622 
4623 			eel_canvas_window_to_world
4624 				(EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
4625 			
4626 			if (gtk_drag_check_threshold (widget, 
4627 						      details->drag_x,
4628 						      details->drag_y,
4629 						      world_x,
4630 						      world_y)) {
4631 				details->drag_started = TRUE;
4632 				details->drag_state = DRAG_STATE_MOVE_OR_COPY;
4633 
4634 				end_renaming_mode (container, TRUE);
4635 			
4636 				eel_canvas_w2c (EEL_CANVAS (container),
4637 						details->drag_x,
4638 						details->drag_y,
4639 						&canvas_x,
4640 						&canvas_y);
4641 
4642 				actions = GDK_ACTION_COPY
4643 					| GDK_ACTION_LINK
4644 					| GDK_ACTION_ASK;
4645 
4646 				if (container->details->drag_allow_moves) {
4647 					actions |= GDK_ACTION_MOVE;
4648 				}
4649 
4650 				nautilus_canvas_dnd_begin_drag (container,
4651 								actions,
4652 								details->drag_button,
4653 								event, 
4654 								canvas_x,
4655 								canvas_y);
4656 				DEBUG ("Beginning drag from canvas container");
4657 			}
4658 			break;
4659 		case DRAG_STATE_STRETCH:
4660 			eel_canvas_window_to_world
4661 				(EEL_CANVAS (container), event->x, event->y, &world_x, &world_y);
4662 			continue_stretching (container, world_x, world_y);
4663 			break;
4664 		default:
4665 			break;
4666 		}
4667 	}
4668 
4669 	return GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->motion_notify_event (widget, event);
4670 }
4671 
4672 static void
4673 nautilus_canvas_container_get_icon_text (NautilusCanvasContainer *container,
4674 					   NautilusCanvasIconData      *data,
4675 					   char                 **editable_text,
4676 					   char                 **additional_text,
4677 					   gboolean               include_invisible)
4678 {
4679 	NautilusCanvasContainerClass *klass;
4680 
4681 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
4682 	g_assert (klass->get_icon_text != NULL);
4683 
4684 	klass->get_icon_text (container, data, editable_text, additional_text, include_invisible);
4685 }
4686 
4687 static gboolean
4688 handle_popups (NautilusCanvasContainer *container,
4689 	       GdkEventKey           *event,
4690 	       const char            *signal)
4691 {
4692 	GdkEventButton button_event = { 0 };
4693 
4694 	/* ensure we clear the drag state before showing the menu */
4695 	clear_drag_state (container);
4696 
4697 	g_signal_emit_by_name (container, signal, &button_event);
4698 
4699 	return TRUE;
4700 }
4701 
4702 static int
4703 key_press_event (GtkWidget *widget,
4704 		 GdkEventKey *event)
4705 {
4706 	NautilusCanvasContainer *container;
4707 	gboolean handled;
4708 
4709 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4710 	handled = FALSE;
4711 
4712 	if (is_renaming (container) || is_renaming_pending (container)) {
4713 		switch (event->keyval) {
4714 		case GDK_KEY_Return:
4715 		case GDK_KEY_KP_Enter:
4716 			end_renaming_mode (container, TRUE);	
4717 			handled = TRUE;
4718 			break;			
4719 		case GDK_KEY_Escape:
4720 			end_renaming_mode (container, FALSE);
4721 			handled = TRUE;
4722 			break;
4723 		default:
4724 			break;
4725 		}
4726 	} else {
4727 		switch (event->keyval) {
4728 		case GDK_KEY_Home:
4729 		case GDK_KEY_KP_Home:
4730 			keyboard_home (container, event);
4731 			handled = TRUE;
4732 			break;
4733 		case GDK_KEY_End:
4734 		case GDK_KEY_KP_End:
4735 			keyboard_end (container, event);
4736 			handled = TRUE;
4737 			break;
4738 		case GDK_KEY_Left:
4739 		case GDK_KEY_KP_Left:
4740 			/* Don't eat Alt-Left, as that is used for history browsing */
4741 			if ((event->state & GDK_MOD1_MASK) == 0) {
4742 				keyboard_left (container, event);
4743 				handled = TRUE;
4744 			}
4745 			break;
4746 		case GDK_KEY_Up:
4747 		case GDK_KEY_KP_Up:
4748 			/* Don't eat Alt-Up, as that is used for alt-shift-Up */
4749 			if ((event->state & GDK_MOD1_MASK) == 0) {
4750 				keyboard_up (container, event);
4751 				handled = TRUE;
4752 			}
4753 			break;
4754 		case GDK_KEY_Right:
4755 		case GDK_KEY_KP_Right:
4756 			/* Don't eat Alt-Right, as that is used for history browsing */
4757 			if ((event->state & GDK_MOD1_MASK) == 0) {
4758 				keyboard_right (container, event);
4759 				handled = TRUE;
4760 			}
4761 			break;
4762 		case GDK_KEY_Down:
4763 		case GDK_KEY_KP_Down:
4764 			/* Don't eat Alt-Down, as that is used for Open */
4765 			if ((event->state & GDK_MOD1_MASK) == 0) {
4766 				keyboard_down (container, event);
4767 				handled = TRUE;
4768 			}
4769 			break;
4770 		case GDK_KEY_space:
4771 			keyboard_space (container, event);
4772 			handled = TRUE;
4773 			break;
4774 #ifndef TAB_NAVIGATION_DISABLED
4775 		case GDK_KEY_Tab:
4776 		case GDK_KEY_ISO_Left_Tab:
4777 			select_previous_or_next_icon (container, 
4778 							(event->state & GDK_SHIFT_MASK) == 0, event);
4779 			handled = TRUE;
4780 			break;
4781 #endif
4782 		case GDK_KEY_Return:
4783 		case GDK_KEY_KP_Enter:
4784 			if ((event->state & GDK_SHIFT_MASK) != 0) {
4785 				activate_selected_items_alternate (container, NULL);
4786 			} else {
4787 				activate_selected_items (container);
4788 			}
4789 			
4790 			handled = TRUE;
4791 			break;
4792  		case GDK_KEY_Escape:
4793 			handled = undo_stretching (container);
4794 			break;
4795  		case GDK_KEY_plus:
4796  		case GDK_KEY_minus:
4797  		case GDK_KEY_equal:
4798  		case GDK_KEY_KP_Add:
4799  		case GDK_KEY_KP_Subtract:
4800  		case GDK_KEY_0:
4801  		case GDK_KEY_KP_0:
4802 			if (event->state & GDK_CONTROL_MASK) {
4803 				handled = keyboard_stretching (container, event);
4804 			}
4805 			break;
4806 		case GDK_KEY_F10:
4807 			/* handle Ctrl+F10 because we want to display the
4808 			 * background popup even if something is selected.
4809 			 * The other cases are handled by popup_menu().
4810 			 */
4811 			if (event->state & GDK_CONTROL_MASK) {
4812 				handled = handle_popups (container, event,
4813 							 "context_click_background");
4814 			}
4815 			break;
4816 		case GDK_KEY_v:
4817 			/* Eat Control + v to not enable type ahead */
4818 			if ((event->state & GDK_CONTROL_MASK) != 0) {
4819 				handled = TRUE;
4820 			}
4821 			break;
4822 		default:
4823 			break;
4824 		}
4825 	}
4826 
4827 	if (!handled) {
4828 		handled = GTK_WIDGET_CLASS (nautilus_canvas_container_parent_class)->key_press_event (widget, event);
4829 	}
4830 
4831 	return handled;
4832 }
4833 
4834 static gboolean
4835 popup_menu (GtkWidget *widget)
4836 {
4837 	NautilusCanvasContainer *container;
4838 
4839 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4840 
4841 	if (has_selection (container)) {
4842 		handle_popups (container, NULL,
4843 			       "context_click_selection");
4844 	} else {
4845 		handle_popups (container, NULL,
4846 			       "context_click_background");
4847 	}
4848 
4849 	return TRUE;
4850 }
4851 
4852 static void
4853 draw_canvas_background (EelCanvas *icon,
4854                         cairo_t   *cr)
4855 {
4856 	/* Don't chain up to the parent to avoid clearing and redrawing */
4857 }
4858 
4859 static void
4860 grab_notify_cb  (GtkWidget        *widget,
4861 		 gboolean          was_grabbed)
4862 {
4863 	NautilusCanvasContainer *container;
4864 
4865 	container = NAUTILUS_CANVAS_CONTAINER (widget);
4866 	
4867 	if (container->details->rubberband_info.active &&
4868 	    !was_grabbed) {
4869 		/* we got a (un)grab-notify during rubberband.
4870 		 * This happens when a new modal dialog shows
4871 		 * up (e.g. authentication or an error). Stop
4872 		 * the rubberbanding so that we can handle the
4873 		 * dialog. */
4874 		stop_rubberbanding (container,
4875 				    GDK_CURRENT_TIME);
4876 	}
4877 }
4878 
4879 static void
4880 text_ellipsis_limit_changed_container_callback (gpointer callback_data)
4881 {
4882 	NautilusCanvasContainer *container;
4883 
4884 	container = NAUTILUS_CANVAS_CONTAINER (callback_data);
4885 	invalidate_label_sizes (container);
4886 	schedule_redo_layout (container);
4887 }
4888 
4889 static GObject*
4890 nautilus_canvas_container_constructor (GType                  type,
4891 				       guint                  n_construct_params,
4892 				       GObjectConstructParam *construct_params)
4893 {
4894 	NautilusCanvasContainer *container;
4895 	GObject *object;
4896 
4897 	object = G_OBJECT_CLASS (nautilus_canvas_container_parent_class)->constructor
4898 		(type,
4899 		 n_construct_params,
4900 		 construct_params);
4901 
4902 	container = NAUTILUS_CANVAS_CONTAINER (object);
4903 	if (nautilus_canvas_container_get_is_desktop (container)) {
4904 		g_signal_connect_swapped (nautilus_desktop_preferences,
4905 					  "changed::" NAUTILUS_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT,
4906 					  G_CALLBACK (text_ellipsis_limit_changed_container_callback),
4907 					  container);
4908 	} else {
4909 		g_signal_connect_swapped (nautilus_icon_view_preferences,
4910 					  "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT,
4911 					  G_CALLBACK (text_ellipsis_limit_changed_container_callback),
4912 					  container);
4913 	}
4914 
4915 	return object;
4916 }
4917 
4918 /* Initialization.  */
4919 
4920 static void
4921 nautilus_canvas_container_class_init (NautilusCanvasContainerClass *class)
4922 {
4923 	GtkWidgetClass *widget_class;
4924 	EelCanvasClass *canvas_class;
4925 
4926 	G_OBJECT_CLASS (class)->constructor = nautilus_canvas_container_constructor;
4927 	G_OBJECT_CLASS (class)->finalize = finalize;
4928 
4929 	/* Signals.  */
4930 
4931 	signals[SELECTION_CHANGED]
4932 		= g_signal_new ("selection_changed",
4933 		                G_TYPE_FROM_CLASS (class),
4934 		                G_SIGNAL_RUN_LAST,
4935 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4936 						 selection_changed),
4937 		                NULL, NULL,
4938 		                g_cclosure_marshal_VOID__VOID,
4939 		                G_TYPE_NONE, 0);
4940 	signals[BUTTON_PRESS]
4941 		= g_signal_new ("button_press",
4942 		                G_TYPE_FROM_CLASS (class),
4943 		                G_SIGNAL_RUN_LAST,
4944 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4945 						 button_press),
4946 		                NULL, NULL,
4947 		                g_cclosure_marshal_generic,
4948 		                G_TYPE_BOOLEAN, 1,
4949 				GDK_TYPE_EVENT);
4950 	signals[ACTIVATE]
4951 		= g_signal_new ("activate",
4952 		                G_TYPE_FROM_CLASS (class),
4953 		                G_SIGNAL_RUN_LAST,
4954 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4955 						 activate),
4956 		                NULL, NULL,
4957 		                g_cclosure_marshal_VOID__POINTER,
4958 		                G_TYPE_NONE, 1,
4959 				G_TYPE_POINTER);
4960 	signals[ACTIVATE_ALTERNATE]
4961 		= g_signal_new ("activate_alternate",
4962 		                G_TYPE_FROM_CLASS (class),
4963 		                G_SIGNAL_RUN_LAST,
4964 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4965 						 activate_alternate),
4966 		                NULL, NULL,
4967 		                g_cclosure_marshal_VOID__POINTER,
4968 		                G_TYPE_NONE, 1,
4969 				G_TYPE_POINTER);
4970 	signals[ACTIVATE_PREVIEWER]
4971 		= g_signal_new ("activate_previewer",
4972 		                G_TYPE_FROM_CLASS (class),
4973 		                G_SIGNAL_RUN_LAST,
4974 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4975 						 activate_previewer),
4976 		                NULL, NULL,
4977 		                g_cclosure_marshal_generic,
4978 		                G_TYPE_NONE, 2,
4979 				G_TYPE_POINTER, G_TYPE_POINTER);
4980 	signals[CONTEXT_CLICK_SELECTION]
4981 		= g_signal_new ("context_click_selection",
4982 		                G_TYPE_FROM_CLASS (class),
4983 		                G_SIGNAL_RUN_LAST,
4984 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4985 						 context_click_selection),
4986 		                NULL, NULL,
4987 		                g_cclosure_marshal_VOID__POINTER,
4988 		                G_TYPE_NONE, 1,
4989 				G_TYPE_POINTER);
4990 	signals[CONTEXT_CLICK_BACKGROUND]
4991 		= g_signal_new ("context_click_background",
4992 		                G_TYPE_FROM_CLASS (class),
4993 		                G_SIGNAL_RUN_LAST,
4994 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
4995 						 context_click_background),
4996 		                NULL, NULL,
4997 		                g_cclosure_marshal_VOID__POINTER,
4998 		                G_TYPE_NONE, 1,
4999 				G_TYPE_POINTER);
5000 	signals[MIDDLE_CLICK]
5001 		= g_signal_new ("middle_click",
5002 		                G_TYPE_FROM_CLASS (class),
5003 		                G_SIGNAL_RUN_LAST,
5004 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5005 						 middle_click),
5006 		                NULL, NULL,
5007 		                g_cclosure_marshal_VOID__POINTER,
5008 		                G_TYPE_NONE, 1,
5009 				G_TYPE_POINTER);
5010 	signals[ICON_POSITION_CHANGED]
5011 		= g_signal_new ("icon_position_changed",
5012 		                G_TYPE_FROM_CLASS (class),
5013 		                G_SIGNAL_RUN_LAST,
5014 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5015 						 icon_position_changed),
5016 		                NULL, NULL,
5017 		                g_cclosure_marshal_generic,
5018 		                G_TYPE_NONE, 2,
5019 				G_TYPE_POINTER,
5020 				G_TYPE_POINTER);
5021 	signals[ICON_STRETCH_STARTED]
5022 		= g_signal_new ("icon_stretch_started",
5023 		                G_TYPE_FROM_CLASS (class),
5024 		                G_SIGNAL_RUN_LAST,
5025 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5026 						 icon_stretch_started),
5027 		                NULL, NULL,
5028 		                g_cclosure_marshal_VOID__POINTER,
5029 		                G_TYPE_NONE, 1,
5030 				G_TYPE_POINTER);
5031 	signals[ICON_STRETCH_ENDED]
5032 		= g_signal_new ("icon_stretch_ended",
5033 		                G_TYPE_FROM_CLASS (class),
5034 		                G_SIGNAL_RUN_LAST,
5035 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5036 						 icon_stretch_ended),
5037 		                NULL, NULL,
5038 		                g_cclosure_marshal_VOID__POINTER,
5039 		                G_TYPE_NONE, 1,
5040 				G_TYPE_POINTER);
5041 	signals[ICON_RENAME_STARTED]
5042 		= g_signal_new ("icon_rename_started",
5043 		                G_TYPE_FROM_CLASS (class),
5044 		                G_SIGNAL_RUN_LAST,
5045 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5046 						 icon_rename_started),
5047 		                NULL, NULL,
5048 		                g_cclosure_marshal_VOID__POINTER,
5049 		                G_TYPE_NONE, 1,
5050 				G_TYPE_POINTER);
5051 	signals[ICON_RENAME_ENDED]
5052 		= g_signal_new ("icon_rename_ended",
5053 		                G_TYPE_FROM_CLASS (class),
5054 		                G_SIGNAL_RUN_LAST,
5055 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5056 						 icon_rename_ended),
5057 		                NULL, NULL,
5058 		                g_cclosure_marshal_generic,
5059 		                G_TYPE_NONE, 2,
5060 				G_TYPE_POINTER,
5061 				G_TYPE_STRING);
5062 	signals[GET_ICON_URI]
5063 		= g_signal_new ("get_icon_uri",
5064 		                G_TYPE_FROM_CLASS (class),
5065 		                G_SIGNAL_RUN_LAST,
5066 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5067 						 get_icon_uri),
5068 		                NULL, NULL,
5069 		                g_cclosure_marshal_generic,
5070 		                G_TYPE_STRING, 1,
5071 				G_TYPE_POINTER);
5072 	signals[GET_ICON_DROP_TARGET_URI]
5073 		= g_signal_new ("get_icon_drop_target_uri",
5074 		                G_TYPE_FROM_CLASS (class),
5075 		                G_SIGNAL_RUN_LAST,
5076 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5077 						 get_icon_drop_target_uri),
5078 		                NULL, NULL,
5079 		                g_cclosure_marshal_generic,
5080 		                G_TYPE_STRING, 1,
5081 				G_TYPE_POINTER);
5082 	signals[MOVE_COPY_ITEMS] 
5083 		= g_signal_new ("move_copy_items",
5084 		                G_TYPE_FROM_CLASS (class),
5085 		                G_SIGNAL_RUN_LAST,
5086 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass, 
5087 						 move_copy_items),
5088 		                NULL, NULL,
5089 		                g_cclosure_marshal_generic,
5090 		                G_TYPE_NONE, 6,
5091 				G_TYPE_POINTER,
5092 				G_TYPE_POINTER,
5093 				G_TYPE_POINTER,
5094 				GDK_TYPE_DRAG_ACTION,
5095 				G_TYPE_INT,
5096 				G_TYPE_INT);
5097 	signals[HANDLE_NETSCAPE_URL]
5098 		= g_signal_new ("handle_netscape_url",
5099 		                G_TYPE_FROM_CLASS (class),
5100 		                G_SIGNAL_RUN_LAST,
5101 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass, 
5102 						 handle_netscape_url),
5103 		                NULL, NULL,
5104 		                g_cclosure_marshal_generic,
5105 		                G_TYPE_NONE, 5,
5106 				G_TYPE_STRING,
5107 				G_TYPE_STRING,
5108 				GDK_TYPE_DRAG_ACTION,
5109 				G_TYPE_INT,
5110 				G_TYPE_INT);
5111 	signals[HANDLE_URI_LIST] 
5112 		= g_signal_new ("handle_uri_list",
5113 		                G_TYPE_FROM_CLASS (class),
5114 		                G_SIGNAL_RUN_LAST,
5115 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass, 
5116 						 handle_uri_list),
5117 		                NULL, NULL,
5118 		                g_cclosure_marshal_generic,
5119 		                G_TYPE_NONE, 5,
5120 				G_TYPE_STRING,
5121 				G_TYPE_STRING,
5122 				GDK_TYPE_DRAG_ACTION,
5123 				G_TYPE_INT,
5124 				G_TYPE_INT);
5125 	signals[HANDLE_TEXT]
5126 		= g_signal_new ("handle_text",
5127 		                G_TYPE_FROM_CLASS (class),
5128 		                G_SIGNAL_RUN_LAST,
5129 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass, 
5130 						 handle_text),
5131 		                NULL, NULL,
5132 		                g_cclosure_marshal_generic,
5133 		                G_TYPE_NONE, 5,
5134 				G_TYPE_STRING,
5135 				G_TYPE_STRING,
5136 				GDK_TYPE_DRAG_ACTION,
5137 				G_TYPE_INT,
5138 				G_TYPE_INT);
5139 	signals[HANDLE_RAW]
5140 		= g_signal_new ("handle_raw",
5141 		                G_TYPE_FROM_CLASS (class),
5142 		                G_SIGNAL_RUN_LAST,
5143 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5144 						 handle_raw),
5145 		                NULL, NULL,
5146 		                g_cclosure_marshal_generic,
5147 		                G_TYPE_NONE, 7,
5148 				G_TYPE_POINTER,
5149 				G_TYPE_INT,
5150 				G_TYPE_STRING,
5151 				G_TYPE_STRING,
5152 				GDK_TYPE_DRAG_ACTION,
5153 				G_TYPE_INT,
5154 				G_TYPE_INT);
5155 	signals[GET_CONTAINER_URI] 
5156 		= g_signal_new ("get_container_uri",
5157 		                G_TYPE_FROM_CLASS (class),
5158 		                G_SIGNAL_RUN_LAST,
5159 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass, 
5160 						 get_container_uri),
5161 		                NULL, NULL,
5162 		                g_cclosure_marshal_generic,
5163 		                G_TYPE_STRING, 0);
5164 	signals[CAN_ACCEPT_ITEM] 
5165 		= g_signal_new ("can_accept_item",
5166 		                G_TYPE_FROM_CLASS (class),
5167 		                G_SIGNAL_RUN_LAST,
5168 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass, 
5169 						 can_accept_item),
5170 		                NULL, NULL,
5171 		                g_cclosure_marshal_generic,
5172 		                G_TYPE_INT, 2,
5173 				G_TYPE_POINTER,
5174 				G_TYPE_STRING);
5175 	signals[GET_STORED_ICON_POSITION]
5176 		= g_signal_new ("get_stored_icon_position",
5177 		                G_TYPE_FROM_CLASS (class),
5178 		                G_SIGNAL_RUN_LAST,
5179 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5180 						 get_stored_icon_position),
5181 		                NULL, NULL,
5182 		                g_cclosure_marshal_generic,
5183 		                G_TYPE_BOOLEAN, 2,
5184 				G_TYPE_POINTER,
5185 				G_TYPE_POINTER);
5186 	signals[GET_STORED_LAYOUT_TIMESTAMP]
5187 		= g_signal_new ("get_stored_layout_timestamp",
5188 		                G_TYPE_FROM_CLASS (class),
5189 		                G_SIGNAL_RUN_LAST,
5190 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5191 						 get_stored_layout_timestamp),
5192 		                NULL, NULL,
5193 		                g_cclosure_marshal_generic,
5194 		                G_TYPE_BOOLEAN, 2,
5195 				G_TYPE_POINTER,
5196 				G_TYPE_POINTER);
5197 	signals[STORE_LAYOUT_TIMESTAMP]
5198 		= g_signal_new ("store_layout_timestamp",
5199 		                G_TYPE_FROM_CLASS (class),
5200 		                G_SIGNAL_RUN_LAST,
5201 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5202 						 store_layout_timestamp),
5203 		                NULL, NULL,
5204 		                g_cclosure_marshal_generic,
5205 		                G_TYPE_BOOLEAN, 2,
5206 				G_TYPE_POINTER,
5207 				G_TYPE_POINTER);
5208 	signals[LAYOUT_CHANGED]
5209 		= g_signal_new ("layout_changed",
5210 		                G_TYPE_FROM_CLASS (class),
5211 		                G_SIGNAL_RUN_LAST,
5212 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5213 						 layout_changed),
5214 		                NULL, NULL,
5215 		                g_cclosure_marshal_VOID__VOID,
5216 		                G_TYPE_NONE, 0);
5217 	signals[BAND_SELECT_STARTED]
5218 		= g_signal_new ("band_select_started",
5219 		                G_TYPE_FROM_CLASS (class),
5220 		                G_SIGNAL_RUN_LAST,
5221 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5222 						 band_select_started),
5223 		                NULL, NULL,
5224 		                g_cclosure_marshal_VOID__VOID,
5225 		                G_TYPE_NONE, 0);
5226 	signals[BAND_SELECT_ENDED]
5227 		= g_signal_new ("band_select_ended",
5228 		                G_TYPE_FROM_CLASS (class),
5229 		                G_SIGNAL_RUN_LAST,
5230 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5231 						 band_select_ended),
5232 		                NULL, NULL,
5233 		                g_cclosure_marshal_VOID__VOID,
5234 		                G_TYPE_NONE, 0);
5235 	signals[ICON_ADDED]
5236 		= g_signal_new ("icon_added",
5237 		                G_TYPE_FROM_CLASS (class),
5238 		                G_SIGNAL_RUN_LAST,
5239 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5240 						 icon_added),
5241 		                NULL, NULL,
5242 		                g_cclosure_marshal_VOID__POINTER,
5243 		                G_TYPE_NONE, 1, G_TYPE_POINTER);
5244 	signals[ICON_REMOVED]
5245 		= g_signal_new ("icon_removed",
5246 		                G_TYPE_FROM_CLASS (class),
5247 		                G_SIGNAL_RUN_LAST,
5248 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5249 						 icon_removed),
5250 		                NULL, NULL,
5251 		                g_cclosure_marshal_VOID__POINTER,
5252 		                G_TYPE_NONE, 1, G_TYPE_POINTER);
5253 
5254 	signals[CLEARED]
5255 		= g_signal_new ("cleared",
5256 		                G_TYPE_FROM_CLASS (class),
5257 		                G_SIGNAL_RUN_LAST,
5258 		                G_STRUCT_OFFSET (NautilusCanvasContainerClass,
5259 						 cleared),
5260 		                NULL, NULL,
5261 		                g_cclosure_marshal_VOID__VOID,
5262 		                G_TYPE_NONE, 0);
5263 
5264 	/* GtkWidget class.  */
5265 
5266 	widget_class = GTK_WIDGET_CLASS (class);
5267 	widget_class->destroy = destroy;
5268 	widget_class->size_allocate = size_allocate;
5269 	widget_class->get_request_mode = get_request_mode;
5270 	widget_class->get_preferred_width = get_prefered_width;
5271 	widget_class->get_preferred_height = get_prefered_height;
5272 	widget_class->realize = realize;
5273 	widget_class->unrealize = unrealize;
5274 	widget_class->button_press_event = button_press_event;
5275 	widget_class->button_release_event = button_release_event;
5276 	widget_class->motion_notify_event = motion_notify_event;
5277 	widget_class->key_press_event = key_press_event;
5278 	widget_class->popup_menu = popup_menu;
5279 	widget_class->style_updated = style_updated;
5280 	widget_class->grab_notify = grab_notify_cb;
5281 	widget_class->get_accessible = get_accessible;
5282 
5283 	canvas_class = EEL_CANVAS_CLASS (class);
5284 	canvas_class->draw_background = draw_canvas_background;
5285 
5286 	gtk_widget_class_install_style_property (widget_class,
5287 						 g_param_spec_boolean ("activate_prelight_icon_label",
5288 								       "Activate Prelight Icon Label",
5289 								       "Whether icon labels should make use of its prelight color in prelight state",
5290 								       FALSE,
5291 								       G_PARAM_READABLE));
5292 }
5293 
5294 static void
5295 update_selected (NautilusCanvasContainer *container)
5296 {
5297 	GList *node;
5298 	NautilusCanvasIcon *icon;
5299 	
5300 	for (node = container->details->icons; node != NULL; node = node->next) {
5301 		icon = node->data;
5302 		if (icon->is_selected) {
5303 			eel_canvas_item_request_update (EEL_CANVAS_ITEM (icon->item));
5304 		}
5305 	}
5306 }
5307 
5308 static gboolean
5309 handle_focus_in_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
5310 {
5311 	update_selected (NAUTILUS_CANVAS_CONTAINER (widget));
5312 
5313 	return FALSE;
5314 }
5315 
5316 static gboolean
5317 handle_focus_out_event (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
5318 {
5319 	/* End renaming and commit change. */
5320 	end_renaming_mode (NAUTILUS_CANVAS_CONTAINER (widget), TRUE);
5321 	update_selected (NAUTILUS_CANVAS_CONTAINER (widget));
5322 
5323 	return FALSE;
5324 }
5325 
5326 
5327 static int text_ellipsis_limits[NAUTILUS_ZOOM_LEVEL_N_ENTRIES];
5328 static int desktop_text_ellipsis_limit;
5329 
5330 static gboolean
5331 get_text_ellipsis_limit_for_zoom (char **strs,
5332 				  const char *zoom_level,
5333 				  int *limit)
5334 {
5335 	char **p;
5336 	char *str;
5337 	gboolean success;
5338 
5339 	success = FALSE;
5340 
5341 	/* default */
5342 	*limit = 3;
5343 
5344 	if (zoom_level != NULL) {
5345 		str = g_strdup_printf ("%s:%%d", zoom_level);
5346 	} else {
5347 		str = g_strdup ("%d");
5348 	}
5349 
5350 	if (strs != NULL) {
5351 		for (p = strs; *p != NULL; p++) {
5352 			if (sscanf (*p, str, limit)) {
5353 				success = TRUE;
5354 			}
5355 		}
5356 	}
5357 
5358 	g_free (str);
5359 
5360 	return success;
5361 }
5362 
5363 static const char * zoom_level_names[] = {
5364 	"smallest",
5365 	"smaller",
5366 	"small",
5367 	"standard",
5368 	"large",
5369 	"larger",
5370 	"largest"
5371 };
5372 
5373 static void
5374 text_ellipsis_limit_changed_callback (gpointer callback_data)
5375 {
5376 	char **pref;
5377 	unsigned int i;
5378 	int one_limit;
5379 
5380 	pref = g_settings_get_strv (nautilus_icon_view_preferences,
5381 				    NAUTILUS_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT);
5382 
5383 	/* set default */
5384 	get_text_ellipsis_limit_for_zoom (pref, NULL, &one_limit);
5385 	for (i = 0; i < NAUTILUS_ZOOM_LEVEL_N_ENTRIES; i++) {
5386 		text_ellipsis_limits[i] = one_limit;
5387 	}
5388 
5389 	/* override for each zoom level */
5390 	for (i = 0; i < G_N_ELEMENTS(zoom_level_names); i++) {
5391 		if (get_text_ellipsis_limit_for_zoom (pref,
5392 						      zoom_level_names[i],
5393 						      &one_limit)) {
5394 			text_ellipsis_limits[i] = one_limit;
5395 		}
5396 	}
5397 
5398 	g_strfreev (pref);
5399 }
5400 
5401 static void
5402 desktop_text_ellipsis_limit_changed_callback (gpointer callback_data)
5403 {
5404 	int pref;
5405 
5406 	pref = g_settings_get_int (nautilus_desktop_preferences, NAUTILUS_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT);
5407 	desktop_text_ellipsis_limit = pref;
5408 }
5409 
5410 static void
5411 nautilus_canvas_container_init (NautilusCanvasContainer *container)
5412 {
5413 	NautilusCanvasContainerDetails *details;
5414 	static gboolean setup_prefs = FALSE;
5415 
5416 	details = g_new0 (NautilusCanvasContainerDetails, 1);
5417 
5418 	details->icon_set = g_hash_table_new (g_direct_hash, g_direct_equal);
5419 	details->layout_timestamp = UNDEFINED_TIME;
5420 	details->zoom_level = NAUTILUS_ZOOM_LEVEL_STANDARD;
5421 
5422 	container->details = details;
5423 
5424 	g_signal_connect (container, "focus-in-event",
5425 			  G_CALLBACK (handle_focus_in_event), NULL);
5426 	g_signal_connect (container, "focus-out-event",
5427 			  G_CALLBACK (handle_focus_out_event), NULL);
5428 
5429 	if (!setup_prefs) {
5430 		g_signal_connect_swapped (nautilus_icon_view_preferences,
5431 					  "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_TEXT_ELLIPSIS_LIMIT,
5432 					  G_CALLBACK (text_ellipsis_limit_changed_callback),
5433 					  NULL);
5434 		text_ellipsis_limit_changed_callback (NULL);
5435 
5436 		g_signal_connect_swapped (nautilus_icon_view_preferences,
5437 					  "changed::" NAUTILUS_PREFERENCES_DESKTOP_TEXT_ELLIPSIS_LIMIT,
5438 					  G_CALLBACK (desktop_text_ellipsis_limit_changed_callback),
5439 					  NULL);
5440 		desktop_text_ellipsis_limit_changed_callback (NULL);
5441 
5442 		setup_prefs = TRUE;
5443 	}
5444 }
5445 
5446 typedef struct {
5447 	NautilusCanvasContainer *container;
5448 	GdkEventButton	      *event;
5449 } ContextMenuParameters;
5450 
5451 static gboolean
5452 handle_canvas_double_click (NautilusCanvasContainer *container,
5453 			    NautilusCanvasIcon *icon,
5454 			    GdkEventButton *event)
5455 {
5456 	NautilusCanvasContainerDetails *details;
5457 
5458 	if (event->button != DRAG_BUTTON) {
5459 		return FALSE;
5460 	}
5461 
5462 	details = container->details;
5463 
5464 	if (!details->single_click_mode &&
5465 	    clicked_within_double_click_interval (container) &&
5466 	    details->double_click_icon[0] == details->double_click_icon[1] &&
5467 	    details->double_click_button[0] == details->double_click_button[1]) {
5468 		if (!button_event_modifies_selection (event)) {
5469 			activate_selected_items (container);
5470 			return TRUE;
5471 		} else if ((event->state & GDK_CONTROL_MASK) == 0 &&
5472 			   (event->state & GDK_SHIFT_MASK) != 0) {
5473 			activate_selected_items_alternate (container, icon);
5474 			return TRUE;
5475 		}
5476 	}
5477 
5478 	return FALSE;
5479 }
5480 
5481 /* NautilusCanvasIcon event handling.  */
5482 
5483 /* Conceptually, pressing button 1 together with CTRL or SHIFT toggles
5484  * selection of a single icon without affecting the other icons;
5485  * without CTRL or SHIFT, it selects a single icon and un-selects all
5486  * the other icons.  But in this latter case, the de-selection should
5487  * only happen when the button is released if the icon is already
5488  * selected, because the user might select multiple icons and drag all
5489  * of them by doing a simple click-drag.
5490  */
5491 
5492 static gboolean
5493 handle_canvas_button_press (NautilusCanvasContainer *container,
5494 			    NautilusCanvasIcon *icon,
5495 			    GdkEventButton *event)
5496 {
5497 	NautilusCanvasContainerDetails *details;
5498 
5499 	details = container->details;
5500 
5501 	if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
5502 		return TRUE;
5503 	}
5504 	
5505 	if (event->button != DRAG_BUTTON
5506 	    && event->button != CONTEXTUAL_MENU_BUTTON
5507 	    && event->button != DRAG_MENU_BUTTON) {
5508 		return TRUE;
5509 	}
5510 
5511 	if ((event->button == DRAG_BUTTON) &&
5512 	    event->type == GDK_BUTTON_PRESS) {
5513 		/* The next double click has to be on this icon */
5514 		details->double_click_icon[1] = details->double_click_icon[0];
5515 		details->double_click_icon[0] = icon;
5516 
5517 		details->double_click_button[1] = details->double_click_button[0];
5518 		details->double_click_button[0] = event->button;
5519 	}
5520 
5521 	if (handle_canvas_double_click (container, icon, event)) {
5522 		/* Double clicking does not trigger a D&D action. */
5523 		details->drag_button = 0;
5524 		details->drag_icon = NULL;
5525 		return TRUE;
5526 	}
5527 
5528 	if (event->button == DRAG_BUTTON
5529 	    || event->button == DRAG_MENU_BUTTON) {
5530 		details->drag_button = event->button;
5531 		details->drag_icon = icon;
5532 		details->drag_x = event->x;
5533 		details->drag_y = event->y;
5534 		details->drag_state = DRAG_STATE_MOVE_OR_COPY;
5535 		details->drag_started = FALSE;
5536 
5537 		/* Check to see if this is a click on the stretch handles.
5538 		 * If so, it won't modify the selection.
5539 		 */
5540 		if (icon == container->details->stretch_icon) {
5541 			if (start_stretching (container)) {
5542 				return TRUE;
5543 			}
5544 		}
5545 	}
5546 
5547 	/* Modify the selection as appropriate. Selection is modified
5548 	 * the same way for contextual menu as it would be without. 
5549 	 */
5550 	details->icon_selected_on_button_down = icon->is_selected;
5551 	
5552 	if ((event->button == DRAG_BUTTON || event->button == MIDDLE_BUTTON) &&
5553 	    (event->state & GDK_SHIFT_MASK) != 0) {
5554 		NautilusCanvasIcon *start_icon;
5555 
5556 		start_icon = details->range_selection_base_icon;
5557 		if (start_icon == NULL || !start_icon->is_selected) {
5558 			start_icon = icon;
5559 			details->range_selection_base_icon = icon;
5560 		} 
5561 		if (select_range (container, start_icon, icon,
5562 				  (event->state & GDK_CONTROL_MASK) == 0)) {
5563 			g_signal_emit (container,
5564 				       signals[SELECTION_CHANGED], 0);
5565 		}
5566 	} else if (!details->icon_selected_on_button_down) {
5567 		details->range_selection_base_icon = icon;
5568 		if (button_event_modifies_selection (event)) {
5569 			icon_toggle_selected (container, icon);
5570 			g_signal_emit (container,
5571 				       signals[SELECTION_CHANGED], 0);
5572 		} else {
5573 			select_one_unselect_others (container, icon);
5574 			g_signal_emit (container,
5575 				       signals[SELECTION_CHANGED], 0);
5576 		}
5577 	}
5578 
5579 	if (event->button == CONTEXTUAL_MENU_BUTTON) {
5580 		clear_drag_state (container);
5581 
5582 		g_signal_emit (container,
5583 			       signals[CONTEXT_CLICK_SELECTION], 0,
5584 			       event);
5585 	}
5586 
5587 
5588 	return TRUE;
5589 }
5590 
5591 static int
5592 item_event_callback (EelCanvasItem *item,
5593 		     GdkEvent *event,
5594 		     gpointer data)
5595 {
5596 	NautilusCanvasContainer *container;
5597 	NautilusCanvasIcon *icon;
5598 
5599 	container = NAUTILUS_CANVAS_CONTAINER (data);
5600 
5601 	icon = NAUTILUS_CANVAS_ITEM (item)->user_data;
5602 	g_assert (icon != NULL);
5603 
5604 	switch (event->type) {
5605 	case GDK_BUTTON_PRESS:
5606 		if (handle_canvas_button_press (container, icon, &event->button)) {
5607 			/* Stop the event from being passed along further. Returning
5608 			 * TRUE ain't enough. 
5609 			 */
5610 			return TRUE;
5611 		}
5612 		return FALSE;
5613 	default:
5614 		return FALSE;
5615 	}
5616 }
5617 
5618 GtkWidget *
5619 nautilus_canvas_container_new (void)
5620 {
5621 	return gtk_widget_new (NAUTILUS_TYPE_CANVAS_CONTAINER, NULL);
5622 }
5623 
5624 /* Clear all of the icons in the container. */
5625 void
5626 nautilus_canvas_container_clear (NautilusCanvasContainer *container)
5627 {
5628 	NautilusCanvasContainerDetails *details;
5629 	NautilusCanvasIcon *icon;
5630 	GList *p;
5631 
5632 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
5633 
5634 	details = container->details;
5635 	details->layout_timestamp = UNDEFINED_TIME;
5636 	details->store_layout_timestamps_when_finishing_new_icons = FALSE;
5637 
5638 	if (details->icons == NULL) {
5639 		return;
5640 	}
5641 
5642 	end_renaming_mode (container, TRUE);
5643 	
5644 	clear_keyboard_focus (container);
5645 	clear_keyboard_rubberband_start (container);
5646 	unschedule_keyboard_icon_reveal (container);
5647 	set_pending_icon_to_reveal (container, NULL);
5648 	details->stretch_icon = NULL;
5649 	details->drop_target = NULL;
5650 
5651 	for (p = details->icons; p != NULL; p = p->next) {
5652 		icon = p->data;
5653 		if (icon->is_monitored) {
5654 			nautilus_canvas_container_stop_monitor_top_left (container,
5655 									 icon->data,
5656 									 icon);
5657 		}
5658 		icon_free (p->data);
5659 	}
5660 	g_list_free (details->icons);
5661 	details->icons = NULL;
5662 	g_list_free (details->new_icons);
5663 	details->new_icons = NULL;
5664 	
5665  	g_hash_table_destroy (details->icon_set);
5666  	details->icon_set = g_hash_table_new (g_direct_hash, g_direct_equal);
5667  
5668 	nautilus_canvas_container_update_scroll_region (container);
5669 }
5670 
5671 gboolean
5672 nautilus_canvas_container_is_empty (NautilusCanvasContainer *container)
5673 {
5674 	return container->details->icons == NULL;
5675 }
5676 
5677 NautilusCanvasIconData *
5678 nautilus_canvas_container_get_first_visible_icon (NautilusCanvasContainer *container)
5679 {
5680 	GList *l;
5681 	NautilusCanvasIcon *icon, *best_icon;
5682 	double x, y;
5683 	double x1, y1, x2, y2;
5684 	double *pos, best_pos;
5685 	double hadj_v, vadj_v, h_page_size;
5686 	gboolean better_icon;
5687 	gboolean compare_lt;
5688 
5689 	hadj_v = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
5690 	vadj_v = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container)));
5691 	h_page_size = gtk_adjustment_get_page_size (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container)));
5692 
5693 	if (nautilus_canvas_container_is_layout_rtl (container)) {
5694 		x = hadj_v + h_page_size - ICON_PAD_LEFT - 1;
5695 		y = vadj_v;
5696 	} else {
5697 		x = hadj_v;
5698 		y = vadj_v;
5699 	}
5700 
5701 	eel_canvas_c2w (EEL_CANVAS (container),
5702 			x, y,
5703 			&x, &y);
5704 
5705 	l = container->details->icons;
5706 	best_icon = NULL;
5707 	best_pos = 0;
5708 	while (l != NULL) {
5709 		icon = l->data;
5710 
5711 		if (icon_is_positioned (icon)) {
5712 			eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item),
5713 						    &x1, &y1, &x2, &y2);
5714 
5715 			compare_lt = FALSE;
5716 			if (nautilus_canvas_container_is_layout_vertical (container)) {
5717 				pos = &x1;
5718 				if (nautilus_canvas_container_is_layout_rtl (container)) {
5719 					compare_lt = TRUE;
5720 					better_icon = x1 < x + ICON_PAD_LEFT;
5721 				} else {
5722 					better_icon = x2 > x + ICON_PAD_LEFT;
5723 				}
5724 			} else {
5725 				pos = &y1;
5726 				better_icon = y2 > y + ICON_PAD_TOP;
5727 			}
5728 			if (better_icon) {
5729 				if (best_icon == NULL) {
5730 					better_icon = TRUE;
5731 				} else if (compare_lt) {
5732 					better_icon = best_pos < *pos;
5733 				} else {
5734 					better_icon = best_pos > *pos;
5735 				}
5736 
5737 				if (better_icon) {
5738 					best_icon = icon;
5739 					best_pos = *pos;
5740 				}
5741 			}
5742 		}
5743 
5744 		l = l->next;
5745 	}
5746 
5747 	return best_icon ? best_icon->data : NULL;
5748 }
5749 
5750 /* puts the icon at the top of the screen */
5751 void
5752 nautilus_canvas_container_scroll_to_canvas (NautilusCanvasContainer  *container,
5753 					    NautilusCanvasIconData       *data)
5754 {
5755 	GList *l;
5756 	NautilusCanvasIcon *icon;
5757 	GtkAdjustment *hadj, *vadj;
5758 	EelIRect bounds;
5759 	GtkAllocation allocation;
5760 
5761 	hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
5762 	vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
5763 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
5764 
5765 	/* We need to force a relayout now if there are updates queued
5766 	 * since we need the final positions */
5767 	nautilus_canvas_container_layout_now (container);
5768 	
5769 	l = container->details->icons;
5770 	while (l != NULL) {
5771 		icon = l->data;
5772 		
5773 		if (icon->data == data &&
5774 		    icon_is_positioned (icon)) {
5775 
5776 			if (nautilus_canvas_container_is_auto_layout (container)) {
5777 				/* ensure that we reveal the entire row/column */
5778 				icon_get_row_and_column_bounds (container, icon, &bounds, TRUE);
5779 			} else {
5780 				item_get_canvas_bounds (EEL_CANVAS_ITEM (icon->item), &bounds, TRUE);
5781 			}
5782 
5783 			if (nautilus_canvas_container_is_layout_vertical (container)) {
5784 				if (nautilus_canvas_container_is_layout_rtl (container)) {
5785 					gtk_adjustment_set_value (hadj, bounds.x1 - allocation.width);
5786 				} else {
5787 					gtk_adjustment_set_value (hadj, bounds.x0);
5788 				}
5789 			} else {
5790 				gtk_adjustment_set_value (vadj, bounds.y0);
5791 			}
5792 		}
5793 		
5794 		l = l->next;
5795 	}
5796 }
5797 
5798 /* Call a function for all the icons. */
5799 typedef struct {
5800 	NautilusCanvasCallback callback;
5801 	gpointer callback_data;
5802 } CallbackAndData;
5803 
5804 static void
5805 call_canvas_callback (gpointer data, gpointer callback_data)
5806 {
5807 	NautilusCanvasIcon *icon;
5808 	CallbackAndData *callback_and_data;
5809 
5810 	icon = data;
5811 	callback_and_data = callback_data;
5812 	(* callback_and_data->callback) (icon->data, callback_and_data->callback_data);
5813 }
5814 
5815 void
5816 nautilus_canvas_container_for_each (NautilusCanvasContainer *container,
5817 				    NautilusCanvasCallback callback,
5818 				    gpointer callback_data)
5819 {
5820 	CallbackAndData callback_and_data;
5821 
5822 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
5823 
5824 	callback_and_data.callback = callback;
5825 	callback_and_data.callback_data = callback_data;
5826 
5827 	g_list_foreach (container->details->icons,
5828 			call_canvas_callback, &callback_and_data);
5829 }
5830 
5831 static int
5832 selection_changed_at_idle_callback (gpointer data)
5833 {
5834 	NautilusCanvasContainer *container;
5835 
5836 	container = NAUTILUS_CANVAS_CONTAINER (data);
5837 	
5838 	g_signal_emit (container,
5839 		       signals[SELECTION_CHANGED], 0);
5840 
5841 	container->details->selection_changed_id = 0;
5842 	return FALSE;
5843 }
5844 
5845 /* utility routine to remove a single icon from the container */
5846 
5847 static void
5848 icon_destroy (NautilusCanvasContainer *container,
5849 	      NautilusCanvasIcon *icon)
5850 {
5851 	NautilusCanvasContainerDetails *details;
5852 	gboolean was_selected;
5853 	NautilusCanvasIcon *icon_to_focus;
5854 	GList *item;
5855  
5856 	details = container->details;
5857 
5858 	item = g_list_find (details->icons, icon);
5859 	item = item->next ? item->next : item->prev;
5860 	icon_to_focus = (item != NULL) ? item->data : NULL;
5861  
5862 	details->icons = g_list_remove (details->icons, icon);
5863 	details->new_icons = g_list_remove (details->new_icons, icon);
5864 	g_hash_table_remove (details->icon_set, icon->data);
5865 
5866 	was_selected = icon->is_selected;
5867 
5868 	if (details->keyboard_focus == icon ||
5869 	    details->keyboard_focus == NULL) {
5870 		if (icon_to_focus != NULL) {
5871 			set_keyboard_focus (container, icon_to_focus);
5872 		} else {
5873 			clear_keyboard_focus (container);
5874 		}
5875 	}
5876 	
5877 	if (details->keyboard_rubberband_start == icon) {
5878 		clear_keyboard_rubberband_start (container);
5879 	}
5880 
5881 	if (details->keyboard_icon_to_reveal == icon) {
5882 		unschedule_keyboard_icon_reveal (container);
5883 	}
5884 	if (details->drag_icon == icon) {
5885 		clear_drag_state (container);
5886 	}
5887 	if (details->drop_target == icon) {
5888 		details->drop_target = NULL;
5889 	}
5890 	if (details->range_selection_base_icon == icon) {
5891 		details->range_selection_base_icon = NULL;
5892 	}
5893 	if (details->pending_icon_to_reveal == icon) {
5894 		set_pending_icon_to_reveal (container, NULL);
5895 	}
5896 	if (details->stretch_icon == icon) {
5897 		details->stretch_icon = NULL;
5898 	}
5899 
5900 	if (icon->is_monitored) {
5901 		nautilus_canvas_container_stop_monitor_top_left (container,
5902 								 icon->data,
5903 								 icon);
5904 	}
5905 	icon_free (icon);
5906 
5907 	if (was_selected) {
5908 		/* Coalesce multiple removals causing multiple selection_changed events */
5909 		details->selection_changed_id = g_idle_add (selection_changed_at_idle_callback, container);
5910 	}
5911 }
5912 
5913 /* activate any selected items in the container */
5914 static void
5915 activate_selected_items (NautilusCanvasContainer *container)
5916 {
5917 	GList *selection;
5918 
5919 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
5920 
5921 	selection = nautilus_canvas_container_get_selection (container);
5922 	if (selection != NULL) {
5923 	  	g_signal_emit (container,
5924 			       signals[ACTIVATE], 0,
5925 			       selection);
5926 	}
5927 	g_list_free (selection);
5928 }
5929 
5930 static void
5931 preview_selected_items (NautilusCanvasContainer *container)
5932 {
5933 	GList *selection;
5934 	GArray *locations;
5935 	gint idx;
5936 
5937 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
5938 
5939 	selection = nautilus_canvas_container_get_selection (container);
5940 	locations = nautilus_canvas_container_get_selected_icon_locations (container);
5941 
5942 	for (idx = 0; idx < locations->len; idx++) {
5943 		GdkPoint *point = &(g_array_index (locations, GdkPoint, idx));
5944 		gint scroll_x, scroll_y;
5945 
5946 		eel_canvas_get_scroll_offsets (EEL_CANVAS (container),
5947 					       &scroll_x, &scroll_y);
5948 
5949 		point->x -= scroll_x;
5950 		point->y -= scroll_y;
5951 	}
5952 
5953 	if (selection != NULL) {
5954 	  	g_signal_emit (container,
5955 			       signals[ACTIVATE_PREVIEWER], 0,
5956 			       selection, locations);
5957 	}
5958 	g_list_free (selection);	
5959 	g_array_unref (locations);
5960 }
5961 
5962 static void
5963 activate_selected_items_alternate (NautilusCanvasContainer *container,
5964 				   NautilusCanvasIcon *icon)
5965 {
5966 	GList *selection;
5967 
5968 	g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
5969 
5970 	if (icon != NULL) {
5971 		selection = g_list_prepend (NULL, icon->data);
5972 	} else {
5973 		selection = nautilus_canvas_container_get_selection (container);
5974 	}
5975 	if (selection != NULL) {
5976 	  	g_signal_emit (container,
5977 			       signals[ACTIVATE_ALTERNATE], 0,
5978 			       selection);
5979 	}
5980 	g_list_free (selection);
5981 }
5982 
5983 static NautilusCanvasIcon *
5984 get_icon_being_renamed (NautilusCanvasContainer *container)
5985 {
5986 	NautilusCanvasIcon *rename_icon;
5987 
5988 	if (!is_renaming (container)) {
5989 		return NULL;
5990 	}
5991 
5992 	g_assert (!has_multiple_selection (container));
5993 
5994 	rename_icon = get_first_selected_icon (container);
5995 	g_assert (rename_icon != NULL);
5996 
5997 	return rename_icon;
5998 }			 
5999 
6000 static NautilusIconInfo *
6001 nautilus_canvas_container_get_icon_images (NautilusCanvasContainer *container,
6002 					     NautilusCanvasIconData      *data,
6003 					     int                    size,
6004 					     char                 **embedded_text,
6005 					     gboolean               for_drag_accept,
6006 					     gboolean               need_large_embeddded_text,
6007 					     gboolean              *embedded_text_needs_loading,
6008 					     gboolean              *has_open_window)
6009 {
6010 	NautilusCanvasContainerClass *klass;
6011 
6012 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
6013 	g_assert (klass->get_icon_images != NULL);
6014 
6015 	return klass->get_icon_images (container, data, size, embedded_text, for_drag_accept, need_large_embeddded_text, embedded_text_needs_loading, has_open_window);
6016 }
6017 
6018 static void
6019 nautilus_canvas_container_freeze_updates (NautilusCanvasContainer *container)
6020 {
6021 	NautilusCanvasContainerClass *klass;
6022 
6023 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
6024 	g_assert (klass->freeze_updates != NULL);
6025 
6026 	klass->freeze_updates (container);
6027 }
6028 
6029 static void
6030 nautilus_canvas_container_unfreeze_updates (NautilusCanvasContainer *container)
6031 {
6032 	NautilusCanvasContainerClass *klass;
6033 
6034 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
6035 	g_assert (klass->unfreeze_updates != NULL);
6036 
6037 	klass->unfreeze_updates (container);
6038 }
6039 
6040 static void
6041 nautilus_canvas_container_start_monitor_top_left (NautilusCanvasContainer *container,
6042 						  NautilusCanvasIconData *data,
6043 						  gconstpointer client,
6044 						  gboolean large_text)
6045 {
6046 	NautilusCanvasContainerClass *klass;
6047 
6048 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
6049 	g_assert (klass->start_monitor_top_left != NULL);
6050 
6051 	klass->start_monitor_top_left (container, data, client, large_text);
6052 }
6053 
6054 static void
6055 nautilus_canvas_container_stop_monitor_top_left (NautilusCanvasContainer *container,
6056 						 NautilusCanvasIconData *data,
6057 						 gconstpointer client)
6058 {
6059 	NautilusCanvasContainerClass *klass;
6060 
6061 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
6062 	g_return_if_fail (klass->stop_monitor_top_left != NULL);
6063 
6064 	klass->stop_monitor_top_left (container, data, client);
6065 }
6066 
6067 
6068 static void
6069 nautilus_canvas_container_prioritize_thumbnailing (NautilusCanvasContainer *container,
6070 						   NautilusCanvasIcon *icon)
6071 {
6072 	NautilusCanvasContainerClass *klass;
6073 
6074 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
6075 	g_assert (klass->prioritize_thumbnailing != NULL);
6076 
6077 	klass->prioritize_thumbnailing (container, icon->data);
6078 }
6079 
6080 static void
6081 nautilus_canvas_container_update_visible_icons (NautilusCanvasContainer *container)
6082 {
6083 	GtkAdjustment *vadj, *hadj;
6084 	double min_y, max_y;
6085 	double min_x, max_x;
6086 	double x0, y0, x1, y1;
6087 	GList *node;
6088 	NautilusCanvasIcon *icon;
6089 	gboolean visible;
6090 	GtkAllocation allocation;
6091 
6092 	hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (container));
6093 	vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (container));
6094 	gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
6095 
6096 	min_x = gtk_adjustment_get_value (hadj);
6097 	max_x = min_x + allocation.width;
6098 	
6099 	min_y = gtk_adjustment_get_value (vadj);
6100 	max_y = min_y + allocation.height;
6101 
6102 	eel_canvas_c2w (EEL_CANVAS (container),
6103 			min_x, min_y, &min_x, &min_y);
6104 	eel_canvas_c2w (EEL_CANVAS (container),
6105 			max_x, max_y, &max_x, &max_y);
6106 	
6107 	/* Do the iteration in reverse to get the render-order from top to
6108 	 * bottom for the prioritized thumbnails.
6109 	 */
6110 	for (node = g_list_last (container->details->icons); node != NULL; node = node->prev) {
6111 		icon = node->data;
6112 
6113 		if (icon_is_positioned (icon)) {
6114 			eel_canvas_item_get_bounds (EEL_CANVAS_ITEM (icon->item),
6115 						    &x0,
6116 						    &y0,
6117 						    &x1,
6118 						    &y1);
6119 			eel_canvas_item_i2w (EEL_CANVAS_ITEM (icon->item)->parent,
6120 					     &x0,
6121 					     &y0);
6122 			eel_canvas_item_i2w (EEL_CANVAS_ITEM (icon->item)->parent,
6123 					     &x1,
6124 					     &y1);
6125 
6126 			if (nautilus_canvas_container_is_layout_vertical (container)) {
6127 				visible = x1 >= min_x && x0 <= max_x;
6128 			} else {
6129 				visible = y1 >= min_y && y0 <= max_y;
6130 			}
6131 
6132 			if (visible) {
6133 				nautilus_canvas_item_set_is_visible (icon->item, TRUE);
6134 				nautilus_canvas_container_prioritize_thumbnailing (container,
6135 										   icon);
6136 			} else {
6137 				nautilus_canvas_item_set_is_visible (icon->item, FALSE);
6138 			}
6139 		}
6140 	}
6141 }
6142 
6143 static void
6144 handle_vadjustment_changed (GtkAdjustment *adjustment,
6145 			    NautilusCanvasContainer *container)
6146 {
6147 	if (!nautilus_canvas_container_is_layout_vertical (container)) {
6148 		nautilus_canvas_container_update_visible_icons (container);
6149 	}
6150 }
6151 
6152 static void
6153 handle_hadjustment_changed (GtkAdjustment *adjustment,
6154 			    NautilusCanvasContainer *container)
6155 {
6156 	if (nautilus_canvas_container_is_layout_vertical (container)) {
6157 		nautilus_canvas_container_update_visible_icons (container);
6158 	}
6159 }
6160 
6161 
6162 void 
6163 nautilus_canvas_container_update_icon (NautilusCanvasContainer *container,
6164 					 NautilusCanvasIcon *icon)
6165 {
6166 	NautilusCanvasContainerDetails *details;
6167 	guint icon_size;
6168 	guint min_image_size, max_image_size;
6169 	NautilusIconInfo *icon_info;
6170 	GdkPoint *attach_points;
6171 	int n_attach_points;
6172 	gboolean has_embedded_text_rect;
6173 	GdkPixbuf *pixbuf;
6174 	char *editable_text, *additional_text;
6175 	char *embedded_text;
6176 	GdkRectangle embedded_text_rect;
6177 	gboolean large_embedded_text;
6178 	gboolean embedded_text_needs_loading;
6179 	gboolean has_open_window;
6180 	
6181 	if (icon == NULL) {
6182 		return;
6183 	}
6184 
6185 	details = container->details;
6186 
6187 	/* compute the maximum size based on the scale factor */
6188 	min_image_size = MINIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit;
6189 	max_image_size = MAX (MAXIMUM_IMAGE_SIZE * EEL_CANVAS (container)->pixels_per_unit, NAUTILUS_ICON_MAXIMUM_SIZE);
6190 
6191 	/* Get the appropriate images for the file. */
6192 	icon_get_size (container, icon, &icon_size);
6193 
6194 	icon_size = MAX (icon_size, min_image_size);
6195 	icon_size = MIN (icon_size, max_image_size);
6196 
6197 	DEBUG ("Icon size, getting for size %d", icon_size);
6198 
6199 	/* Get the icons. */
6200 	embedded_text = NULL;
6201 	large_embedded_text = icon_size > ICON_SIZE_FOR_LARGE_EMBEDDED_TEXT;
6202 	icon_info = nautilus_canvas_container_get_icon_images (container, icon->data, icon_size,
6203 							       &embedded_text,
6204 							       icon == details->drop_target,							     
6205 							       large_embedded_text, &embedded_text_needs_loading,
6206 							       &has_open_window);
6207 
6208 	pixbuf = nautilus_icon_info_get_pixbuf (icon_info);
6209 
6210 	nautilus_icon_info_get_attach_points (icon_info, &attach_points, &n_attach_points);
6211 	has_embedded_text_rect = nautilus_icon_info_get_embedded_rect (icon_info,
6212 									 &embedded_text_rect);
6213 
6214 	g_object_unref (icon_info);
6215  
6216 	if (has_embedded_text_rect && embedded_text_needs_loading) {
6217 		icon->is_monitored = TRUE;
6218 		nautilus_canvas_container_start_monitor_top_left (container, icon->data, icon, large_embedded_text);
6219 	}
6220 	
6221 	nautilus_canvas_container_get_icon_text (container,
6222 						   icon->data,
6223 						   &editable_text,
6224 						   &additional_text,
6225 						   FALSE);
6226 
6227 	/* If name of icon being renamed was changed from elsewhere, end renaming mode. 
6228 	 * Alternatively, we could replace the characters in the editable text widget
6229 	 * with the new name, but that could cause timing problems if the user just
6230 	 * happened to be typing at that moment.
6231 	 */
6232 	if (icon == get_icon_being_renamed (container) &&
6233 	    g_strcmp0 (editable_text,
6234 		       nautilus_canvas_item_get_editable_text (icon->item)) != 0) {
6235 		end_renaming_mode (container, FALSE);
6236 	}
6237 
6238 	eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item),
6239 			     "editable_text", editable_text,
6240 			     "additional_text", additional_text,
6241 			     "highlighted_for_drop", icon == details->drop_target,
6242 			     NULL);
6243 
6244 	nautilus_canvas_item_set_image (icon->item, pixbuf);
6245 	nautilus_canvas_item_set_attach_points (icon->item, attach_points, n_attach_points);
6246 	nautilus_canvas_item_set_embedded_text_rect (icon->item, &embedded_text_rect);
6247 	nautilus_canvas_item_set_embedded_text (icon->item, embedded_text);
6248 
6249 	/* Let the pixbufs go. */
6250 	g_object_unref (pixbuf);
6251 
6252 	g_free (editable_text);
6253 	g_free (additional_text);
6254 }
6255 
6256 static gboolean
6257 assign_icon_position (NautilusCanvasContainer *container,
6258 			NautilusCanvasIcon *icon)
6259 {
6260 	gboolean have_stored_position;
6261 	NautilusCanvasPosition position;
6262 
6263 	/* Get the stored position. */
6264 	have_stored_position = FALSE;
6265 	position.scale = 1.0;
6266 	g_signal_emit (container,
6267 		       signals[GET_STORED_ICON_POSITION], 0,
6268 		       icon->data,
6269 		       &position,
6270 		       &have_stored_position);
6271 	icon->scale = position.scale;
6272 	if (!container->details->auto_layout) {
6273 		if (have_stored_position) {
6274 			icon_set_position (icon, position.x, position.y);
6275 			icon->saved_ltr_x = icon->x;
6276 		} else {
6277 			return FALSE;
6278 		}
6279 	}
6280 	return TRUE;
6281 }
6282 
6283 static void
6284 finish_adding_icon (NautilusCanvasContainer *container,
6285 		    NautilusCanvasIcon *icon)
6286 {
6287 	nautilus_canvas_container_update_icon (container, icon);
6288 	eel_canvas_item_show (EEL_CANVAS_ITEM (icon->item));
6289 
6290 	g_signal_connect_object (icon->item, "event",
6291 				 G_CALLBACK (item_event_callback), container, 0);
6292 
6293 	g_signal_emit (container, signals[ICON_ADDED], 0, icon->data);
6294 }
6295 
6296 static void
6297 finish_adding_new_icons (NautilusCanvasContainer *container)
6298 {
6299 	GList *p, *new_icons, *no_position_icons, *semi_position_icons;
6300 	NautilusCanvasIcon *icon;
6301 	double bottom;
6302 
6303 	new_icons = container->details->new_icons;
6304 	container->details->new_icons = NULL;
6305 
6306 	/* Position most icons (not unpositioned manual-layout icons). */
6307 	new_icons = g_list_reverse (new_icons);
6308 	no_position_icons = semi_position_icons = NULL;
6309 	for (p = new_icons; p != NULL; p = p->next) {
6310 		icon = p->data;
6311 		if (icon->has_lazy_position) {
6312 			assign_icon_position (container, icon);
6313 			semi_position_icons = g_list_prepend (semi_position_icons, icon);
6314 		} else if (!assign_icon_position (container, icon)) {
6315 			no_position_icons = g_list_prepend (no_position_icons, icon);
6316 		}
6317 
6318 		finish_adding_icon (container, icon);
6319 	}
6320 	g_list_free (new_icons);
6321 
6322 	if (semi_position_icons != NULL) {
6323 		PlacementGrid *grid;
6324 		time_t now;
6325 		gboolean dummy;
6326 
6327 		g_assert (!container->details->auto_layout);
6328 
6329 		semi_position_icons = g_list_reverse (semi_position_icons);
6330 
6331 		/* This is currently only used on the desktop.
6332 		 * Thus, we pass FALSE for tight, like lay_down_icons_tblr */
6333 		grid = placement_grid_new (container, FALSE);
6334 
6335 		for (p = container->details->icons; p != NULL; p = p->next) {
6336 			icon = p->data;
6337 
6338 			if (icon_is_positioned (icon) && !icon->has_lazy_position) {
6339 				placement_grid_mark_icon (grid, icon);
6340 			}
6341 		}
6342 
6343 		now = time (NULL);
6344 
6345 		for (p = semi_position_icons; p != NULL; p = p->next) {
6346 			NautilusCanvasIcon *icon;
6347 			NautilusCanvasPosition position;
6348 			int x, y;
6349 
6350 			icon = p->data;
6351 			x = icon->x;
6352 			y = icon->y;
6353 
6354 			find_empty_location (container, grid, 
6355 					     icon, x, y, &x, &y);
6356 
6357 			icon_set_position (icon, x, y);
6358 
6359 			position.x = icon->x;
6360 			position.y = icon->y;
6361 			position.scale = icon->scale;
6362 			placement_grid_mark_icon (grid, icon);
6363 			g_signal_emit (container, signals[ICON_POSITION_CHANGED], 0,
6364 				       icon->data, &position);
6365 			g_signal_emit (container, signals[STORE_LAYOUT_TIMESTAMP], 0,
6366 				       icon->data, &now, &dummy);
6367 
6368 			/* ensure that next time we run this code, the formerly semi-positioned
6369 			 * icons are treated as being positioned. */
6370 			icon->has_lazy_position = FALSE;
6371 		}
6372 
6373 		placement_grid_free (grid);
6374 
6375 		g_list_free (semi_position_icons);
6376 	}
6377 
6378 	/* Position the unpositioned manual layout icons. */
6379 	if (no_position_icons != NULL) {
6380 		g_assert (!container->details->auto_layout);
6381 		
6382 		sort_icons (container, &no_position_icons);
6383 		if (nautilus_canvas_container_get_is_desktop (container)) {
6384 			lay_down_icons (container, no_position_icons, CONTAINER_PAD_TOP);
6385 		} else {
6386 			get_all_icon_bounds (container, NULL, NULL, NULL, &bottom, BOUNDS_USAGE_FOR_LAYOUT);
6387 			lay_down_icons (container, no_position_icons, bottom + ICON_PAD_BOTTOM);
6388 		}
6389 		g_list_free (no_position_icons);
6390 	}
6391 
6392 	if (container->details->store_layout_timestamps_when_finishing_new_icons) {
6393 		store_layout_timestamps_now (container);
6394 		container->details->store_layout_timestamps_when_finishing_new_icons = FALSE;
6395 	}
6396 }
6397 
6398 static gboolean
6399 is_old_or_unknown_icon_data (NautilusCanvasContainer *container,
6400 			       NautilusCanvasIconData *data)
6401 {
6402 	time_t timestamp;
6403 	gboolean success;
6404 
6405 	if (container->details->layout_timestamp == UNDEFINED_TIME) {
6406 		/* don't know */
6407 		return FALSE;
6408 	}
6409 
6410 	g_signal_emit (container,
6411 		       signals[GET_STORED_LAYOUT_TIMESTAMP], 0,
6412 		       data, &timestamp, &success);
6413 	return (!success || timestamp < container->details->layout_timestamp);
6414 }
6415 
6416 /**
6417  * nautilus_canvas_container_add:
6418  * @container: A NautilusCanvasContainer
6419  * @data: Icon data.
6420  * 
6421  * Add icon to represent @data to container.
6422  * Returns FALSE if there was already such an icon.
6423  **/
6424 gboolean
6425 nautilus_canvas_container_add (NautilusCanvasContainer *container,
6426 			       NautilusCanvasIconData *data)
6427 {
6428 	NautilusCanvasContainerDetails *details;
6429 	NautilusCanvasIcon *icon;
6430 	EelCanvasItem *band, *item;
6431 	
6432 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
6433 	g_return_val_if_fail (data != NULL, FALSE);
6434 
6435 	details = container->details;
6436 
6437 	if (g_hash_table_lookup (details->icon_set, data) != NULL) {
6438 		return FALSE;
6439 	}
6440 
6441 	/* Create the new icon, including the canvas item. */
6442 	icon = g_new0 (NautilusCanvasIcon, 1);
6443 	icon->data = data;
6444 	icon->x = ICON_UNPOSITIONED_VALUE;
6445 	icon->y = ICON_UNPOSITIONED_VALUE;
6446 
6447 	/* Whether the saved icon position should only be used
6448 	 * if the previous icon position is free. If the position
6449 	 * is occupied, another position near the last one will
6450 	 */
6451 	icon->has_lazy_position = is_old_or_unknown_icon_data (container, data);
6452 	icon->scale = 1.0;
6453  	icon->item = NAUTILUS_CANVAS_ITEM
6454 		(eel_canvas_item_new (EEL_CANVAS_GROUP (EEL_CANVAS (container)->root),
6455 				      nautilus_canvas_item_get_type (),
6456 				      "visible", FALSE,
6457 				      NULL));
6458 	icon->item->user_data = icon;
6459 
6460 	/* Make sure the icon is under the selection_rectangle */
6461 	item = EEL_CANVAS_ITEM (icon->item);
6462 	band = NAUTILUS_CANVAS_CONTAINER (item->canvas)->details->rubberband_info.selection_rectangle;
6463 	if (band) {
6464 		eel_canvas_item_send_behind (item, band);
6465 	}
6466 	
6467 	/* Put it on both lists. */
6468 	details->icons = g_list_prepend (details->icons, icon);
6469 	details->new_icons = g_list_prepend (details->new_icons, icon);
6470 
6471 	g_hash_table_insert (details->icon_set, data, icon);
6472 
6473 	details->needs_resort = TRUE;
6474 
6475 	/* Run an idle function to add the icons. */
6476 	schedule_redo_layout (container);
6477 	
6478 	return TRUE;
6479 }
6480 
6481 void
6482 nautilus_canvas_container_layout_now (NautilusCanvasContainer *container)
6483 {
6484 	if (container->details->idle_id != 0) {
6485 		unschedule_redo_layout (container);
6486 		redo_layout_internal (container);
6487 	}
6488 
6489 	/* Also need to make sure we're properly resized, for instance
6490 	 * newly added files may trigger a change in the size allocation and
6491 	 * thus toggle scrollbars on */
6492 	gtk_container_check_resize (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (container))));
6493 }
6494 
6495 /**
6496  * nautilus_canvas_container_remove:
6497  * @container: A NautilusCanvasContainer.
6498  * @data: Icon data.
6499  * 
6500  * Remove the icon with this data.
6501  **/
6502 gboolean
6503 nautilus_canvas_container_remove (NautilusCanvasContainer *container,
6504 				  NautilusCanvasIconData *data)
6505 {
6506 	NautilusCanvasIcon *icon;
6507 
6508 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
6509 	g_return_val_if_fail (data != NULL, FALSE);
6510 
6511 	end_renaming_mode (container, FALSE);
6512 		
6513 	icon = g_hash_table_lookup (container->details->icon_set, data);
6514 
6515 	if (icon == NULL) {
6516 		return FALSE;
6517 	}
6518 
6519 	icon_destroy (container, icon);
6520 	schedule_redo_layout (container);
6521 
6522 	g_signal_emit (container, signals[ICON_REMOVED], 0, icon);
6523 
6524 	return TRUE;
6525 }
6526 
6527 /**
6528  * nautilus_canvas_container_request_update:
6529  * @container: A NautilusCanvasContainer.
6530  * @data: Icon data.
6531  * 
6532  * Update the icon with this data.
6533  **/
6534 void
6535 nautilus_canvas_container_request_update (NautilusCanvasContainer *container,
6536 					  NautilusCanvasIconData *data)
6537 {
6538 	NautilusCanvasIcon *icon;
6539 
6540 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6541 	g_return_if_fail (data != NULL);
6542 
6543 	icon = g_hash_table_lookup (container->details->icon_set, data);
6544 
6545 	if (icon != NULL) {
6546 		nautilus_canvas_container_update_icon (container, icon);
6547 		container->details->needs_resort = TRUE;
6548 		schedule_redo_layout (container);
6549 	}
6550 }
6551 
6552 /* zooming */
6553 
6554 NautilusZoomLevel
6555 nautilus_canvas_container_get_zoom_level (NautilusCanvasContainer *container)
6556 {
6557         return container->details->zoom_level;
6558 }
6559 
6560 void
6561 nautilus_canvas_container_set_zoom_level (NautilusCanvasContainer *container, int new_level)
6562 {
6563 	NautilusCanvasContainerDetails *details;
6564         int pinned_level;
6565 	double pixels_per_unit;
6566 	
6567 	details = container->details;
6568 
6569 	end_renaming_mode (container, TRUE);
6570 		
6571 	pinned_level = new_level;
6572         if (pinned_level < NAUTILUS_ZOOM_LEVEL_SMALLEST) {
6573 		pinned_level = NAUTILUS_ZOOM_LEVEL_SMALLEST;
6574         } else if (pinned_level > NAUTILUS_ZOOM_LEVEL_LARGEST) {
6575         	pinned_level = NAUTILUS_ZOOM_LEVEL_LARGEST;
6576 	}
6577 
6578         if (pinned_level == details->zoom_level) {
6579 		return;
6580 	}
6581 	
6582 	details->zoom_level = pinned_level;
6583 	
6584 	pixels_per_unit = (double) nautilus_get_icon_size_for_zoom_level (pinned_level)
6585 		/ NAUTILUS_ICON_SIZE_STANDARD;
6586 	eel_canvas_set_pixels_per_unit (EEL_CANVAS (container), pixels_per_unit);
6587 
6588 	invalidate_labels (container);
6589 	nautilus_canvas_container_request_update_all (container);
6590 }
6591 
6592 /**
6593  * nautilus_canvas_container_request_update_all:
6594  * For each icon, synchronizes the displayed information (image, text) with the
6595  * information from the model.
6596  * 
6597  * @container: An canvas container.
6598  **/
6599 void
6600 nautilus_canvas_container_request_update_all (NautilusCanvasContainer *container)
6601 {
6602 	GList *node;
6603 	NautilusCanvasIcon *icon;
6604 
6605 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6606 
6607 	for (node = container->details->icons; node != NULL; node = node->next) {
6608 		icon = node->data;
6609 		nautilus_canvas_container_update_icon (container, icon);
6610 	}
6611 
6612 	container->details->needs_resort = TRUE;
6613 	redo_layout (container);
6614 }
6615 
6616 /**
6617  * nautilus_canvas_container_reveal:
6618  * Change scroll position as necessary to reveal the specified item.
6619  */
6620 void
6621 nautilus_canvas_container_reveal (NautilusCanvasContainer *container, NautilusCanvasIconData *data)
6622 {
6623 	NautilusCanvasIcon *icon;
6624 
6625 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6626 	g_return_if_fail (data != NULL);
6627 
6628 	icon = g_hash_table_lookup (container->details->icon_set, data);
6629 
6630 	if (icon != NULL) {
6631 		reveal_icon (container, icon);
6632 	}
6633 }
6634 
6635 /**
6636  * nautilus_canvas_container_get_selection:
6637  * @container: An canvas container.
6638  * 
6639  * Get a list of the icons currently selected in @container.
6640  * 
6641  * Return value: A GList of the programmer-specified data associated to each
6642  * selected icon, or NULL if no canvas is selected.  The caller is expected to
6643  * free the list when it is not needed anymore.
6644  **/
6645 GList *
6646 nautilus_canvas_container_get_selection (NautilusCanvasContainer *container)
6647 {
6648 	GList *list, *p;
6649 
6650 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL);
6651 
6652 	list = NULL;
6653 	for (p = container->details->icons; p != NULL; p = p->next) {
6654 		NautilusCanvasIcon *icon;
6655 
6656 		icon = p->data;
6657 		if (icon->is_selected) {
6658 			list = g_list_prepend (list, icon->data);
6659 		}
6660 	}
6661 
6662 	return g_list_reverse (list);
6663 }
6664 
6665 static GList *
6666 nautilus_canvas_container_get_selected_icons (NautilusCanvasContainer *container)
6667 {
6668 	GList *list, *p;
6669 
6670 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL);
6671 
6672 	list = NULL;
6673 	for (p = container->details->icons; p != NULL; p = p->next) {
6674 		NautilusCanvasIcon *icon;
6675 
6676 		icon = p->data;
6677 		if (icon->is_selected) {
6678 			list = g_list_prepend (list, icon);
6679 		}
6680 	}
6681 
6682 	return g_list_reverse (list);
6683 }
6684 
6685 /**
6686  * nautilus_canvas_container_invert_selection:
6687  * @container: An canvas container.
6688  * 
6689  * Inverts the selection in @container.
6690  * 
6691  **/
6692 void
6693 nautilus_canvas_container_invert_selection (NautilusCanvasContainer *container)
6694 {
6695 	GList *p;
6696 
6697 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6698 
6699 	for (p = container->details->icons; p != NULL; p = p->next) {
6700 		NautilusCanvasIcon *icon;
6701 
6702 		icon = p->data;
6703 		icon_toggle_selected (container, icon);
6704 	}
6705 
6706 	g_signal_emit (container, signals[SELECTION_CHANGED], 0);
6707 }
6708 
6709 
6710 /* Returns an array of GdkPoints of locations of the icons. */
6711 static GArray *
6712 nautilus_canvas_container_get_icon_locations (NautilusCanvasContainer *container,
6713 						GList *icons)
6714 {
6715 	GArray *result;
6716 	GList *node;
6717 	int index;
6718 		
6719 	result = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
6720 	result = g_array_set_size (result, g_list_length (icons));
6721 		
6722 	for (index = 0, node = icons; node != NULL; index++, node = node->next) {
6723 	     	g_array_index (result, GdkPoint, index).x =
6724 	     		((NautilusCanvasIcon *)node->data)->x;
6725 	     	g_array_index (result, GdkPoint, index).y =
6726 			((NautilusCanvasIcon *)node->data)->y;
6727 	}
6728 
6729 	return result;
6730 }
6731 
6732 /**
6733  * nautilus_canvas_container_get_selected_icon_locations:
6734  * @container: An canvas container widget.
6735  * 
6736  * Returns an array of GdkPoints of locations of the selected icons.
6737  **/
6738 GArray *
6739 nautilus_canvas_container_get_selected_icon_locations (NautilusCanvasContainer *container)
6740 {
6741 	GArray *result;
6742 	GList *icons;
6743 
6744 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL);
6745 
6746 	icons = nautilus_canvas_container_get_selected_icons (container);
6747 	result = nautilus_canvas_container_get_icon_locations (container, icons);
6748 	g_list_free (icons);
6749 	
6750 	return result;
6751 }
6752 
6753 /**
6754  * nautilus_canvas_container_select_all:
6755  * @container: An canvas container widget.
6756  * 
6757  * Select all the icons in @container at once.
6758  **/
6759 void
6760 nautilus_canvas_container_select_all (NautilusCanvasContainer *container)
6761 {
6762 	gboolean selection_changed;
6763 	GList *p;
6764 	NautilusCanvasIcon *icon;
6765 
6766 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6767 
6768 	selection_changed = FALSE;
6769 
6770 	for (p = container->details->icons; p != NULL; p = p->next) {
6771 		icon = p->data;
6772 		
6773 		selection_changed |= icon_set_selected (container, icon, TRUE);
6774 	}
6775 
6776 	if (selection_changed) {
6777 		g_signal_emit (container,
6778 			       signals[SELECTION_CHANGED], 0);
6779 	}
6780 }
6781 
6782 /**
6783  * nautilus_canvas_container_select_first:
6784  * @container: An canvas container widget.
6785  * 
6786  * Select the first icon in @container.
6787  **/
6788 void
6789 nautilus_canvas_container_select_first (NautilusCanvasContainer *container)
6790 {
6791 	gboolean selection_changed;
6792 	NautilusCanvasIcon *icon;
6793 
6794 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6795 
6796 	selection_changed = FALSE;
6797 
6798 	if (container->details->needs_resort) {
6799 		resort (container);
6800 		container->details->needs_resort = FALSE;
6801 	}
6802 
6803 	icon = g_list_nth_data (container->details->icons, 0);
6804 	if (icon) {
6805 		selection_changed |= icon_set_selected (container, icon, TRUE);
6806 	}
6807 
6808 	if (selection_changed) {
6809 		g_signal_emit (container,
6810 			       signals[SELECTION_CHANGED], 0);
6811 	}
6812 }
6813 
6814 /**
6815  * nautilus_canvas_container_set_selection:
6816  * @container: An canvas container widget.
6817  * @selection: A list of NautilusCanvasIconData *.
6818  * 
6819  * Set the selection to exactly the icons in @container which have
6820  * programmer data matching one of the items in @selection.
6821  **/
6822 void
6823 nautilus_canvas_container_set_selection (NautilusCanvasContainer *container,
6824 					 GList *selection)
6825 {
6826 	gboolean selection_changed;
6827 	GHashTable *hash;
6828 	GList *p;
6829 	gboolean res;
6830 	NautilusCanvasIcon *icon, *selected_icon;
6831 
6832 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6833 
6834 	selection_changed = FALSE;
6835 	selected_icon = NULL;
6836 
6837 	hash = g_hash_table_new (NULL, NULL);
6838 	for (p = selection; p != NULL; p = p->next) {
6839 		g_hash_table_insert (hash, p->data, p->data);
6840 	}
6841 	for (p = container->details->icons; p != NULL; p = p->next) {
6842 		icon = p->data;
6843 		
6844 		res = icon_set_selected
6845 			(container, icon,
6846 			 g_hash_table_lookup (hash, icon->data) != NULL);
6847 		selection_changed |= res;
6848 
6849 		if (res) {
6850 			selected_icon = icon;
6851 		}
6852 	}
6853 	g_hash_table_destroy (hash);
6854 
6855 	if (selection_changed) {
6856 		/* if only one item has been selected, use it as range
6857 		 * selection base (cf. handle_canvas_button_press) */
6858 		if (g_list_length (selection) == 1) {
6859 			container->details->range_selection_base_icon = selected_icon;
6860 		}
6861 
6862 		g_signal_emit (container,
6863 			       signals[SELECTION_CHANGED], 0);
6864 	}
6865 }
6866 
6867 /**
6868  * nautilus_canvas_container_select_list_unselect_others.
6869  * @container: An canvas container widget.
6870  * @selection: A list of NautilusCanvasIcon *.
6871  * 
6872  * Set the selection to exactly the icons in @selection.
6873  **/
6874 void
6875 nautilus_canvas_container_select_list_unselect_others (NautilusCanvasContainer *container,
6876 						       GList *selection)
6877 {
6878 	gboolean selection_changed;
6879 	GHashTable *hash;
6880 	GList *p;
6881 	NautilusCanvasIcon *icon;
6882 
6883 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
6884 
6885 	selection_changed = FALSE;
6886 
6887 	hash = g_hash_table_new (NULL, NULL);
6888 	for (p = selection; p != NULL; p = p->next) {
6889 		g_hash_table_insert (hash, p->data, p->data);
6890 	}
6891 	for (p = container->details->icons; p != NULL; p = p->next) {
6892 		icon = p->data;
6893 		
6894 		selection_changed |= icon_set_selected
6895 			(container, icon,
6896 			 g_hash_table_lookup (hash, icon) != NULL);
6897 	}
6898 	g_hash_table_destroy (hash);
6899 
6900 	if (selection_changed) {
6901 		g_signal_emit (container,
6902 			       signals[SELECTION_CHANGED], 0);
6903 	}
6904 }
6905 
6906 /**
6907  * nautilus_canvas_container_unselect_all:
6908  * @container: An canvas container widget.
6909  * 
6910  * Deselect all the icons in @container.
6911  **/
6912 void
6913 nautilus_canvas_container_unselect_all (NautilusCanvasContainer *container)
6914 {
6915 	if (unselect_all (container)) {
6916 		g_signal_emit (container,
6917 			       signals[SELECTION_CHANGED], 0);
6918 	}
6919 }
6920 
6921 /**
6922  * nautilus_canvas_container_get_icon_by_uri:
6923  * @container: An canvas container widget.
6924  * @uri: The uri of an canvas to find.
6925  * 
6926  * Locate an icon, given the URI. The URI must match exactly.
6927  * Later we may have to have some way of figuring out if the
6928  * URI specifies the same object that does not require an exact match.
6929  **/
6930 NautilusCanvasIcon *
6931 nautilus_canvas_container_get_icon_by_uri (NautilusCanvasContainer *container,
6932 					     const char *uri)
6933 {
6934 	NautilusCanvasContainerDetails *details;
6935 	GList *p;
6936 
6937 	/* Eventually, we must avoid searching the entire canvas list,
6938 	   but it's OK for now.
6939 	   A hash table mapping uri to canvas is one possibility.
6940 	*/
6941 
6942 	details = container->details;
6943 
6944 	for (p = details->icons; p != NULL; p = p->next) {
6945 		NautilusCanvasIcon *icon;
6946 		char *icon_uri;
6947 		gboolean is_match;
6948 
6949 		icon = p->data;
6950 
6951 		icon_uri = nautilus_canvas_container_get_icon_uri
6952 			(container, icon);
6953 		is_match = strcmp (uri, icon_uri) == 0;
6954 		g_free (icon_uri);
6955 
6956 		if (is_match) {
6957 			return icon;
6958 		}
6959 	}
6960 
6961 	return NULL;
6962 }
6963 
6964 static NautilusCanvasIcon *
6965 get_nth_selected_icon (NautilusCanvasContainer *container, int index)
6966 {
6967 	GList *p;
6968 	NautilusCanvasIcon *icon;
6969 	int selection_count;
6970 
6971 	g_assert (index > 0);
6972 
6973 	/* Find the nth selected icon. */
6974 	selection_count = 0;
6975 	for (p = container->details->icons; p != NULL; p = p->next) {
6976 		icon = p->data;
6977 		if (icon->is_selected) {
6978 			if (++selection_count == index) {
6979 				return icon;
6980 			}
6981 		}
6982 	}
6983 	return NULL;
6984 }
6985 
6986 static NautilusCanvasIcon *
6987 get_first_selected_icon (NautilusCanvasContainer *container)
6988 {
6989         return get_nth_selected_icon (container, 1);
6990 }
6991 
6992 static gboolean
6993 has_multiple_selection (NautilusCanvasContainer *container)
6994 {
6995         return get_nth_selected_icon (container, 2) != NULL;
6996 }
6997 
6998 static gboolean
6999 all_selected (NautilusCanvasContainer *container)
7000 {
7001 	GList *p;
7002 	NautilusCanvasIcon *icon;
7003 
7004 	for (p = container->details->icons; p != NULL; p = p->next) {
7005 		icon = p->data;
7006 		if (!icon->is_selected) {
7007 			return FALSE;
7008 		}
7009 	}
7010 	return TRUE;
7011 }
7012 
7013 static gboolean
7014 has_selection (NautilusCanvasContainer *container)
7015 {
7016         return get_nth_selected_icon (container, 1) != NULL;
7017 }
7018 
7019 /**
7020  * nautilus_canvas_container_show_stretch_handles:
7021  * @container: An canvas container widget.
7022  * 
7023  * Makes stretch handles visible on the first selected icon.
7024  **/
7025 void
7026 nautilus_canvas_container_show_stretch_handles (NautilusCanvasContainer *container)
7027 {
7028 	NautilusCanvasContainerDetails *details;
7029 	NautilusCanvasIcon *icon;
7030 	guint initial_size;
7031 	
7032 	icon = get_first_selected_icon (container);
7033 	if (icon == NULL) {
7034 		return;
7035 	}
7036 
7037 	/* Check if it already has stretch handles. */
7038 	details = container->details;
7039 	if (details->stretch_icon == icon) {
7040 		return;
7041 	}
7042 
7043 	/* Get rid of the existing stretch handles and put them on the new canvas. */
7044 	if (details->stretch_icon != NULL) {
7045 		nautilus_canvas_item_set_show_stretch_handles
7046 			(details->stretch_icon->item, FALSE);
7047 		ungrab_stretch_icon (container);
7048 		emit_stretch_ended (container, details->stretch_icon);
7049 	}
7050 	nautilus_canvas_item_set_show_stretch_handles (icon->item, TRUE);
7051 	details->stretch_icon = icon;
7052 	
7053 	icon_get_size (container, icon, &initial_size);
7054 
7055 	/* only need to keep size in one dimension, since they are constrained to be the same */
7056 	container->details->stretch_initial_x = icon->x;
7057 	container->details->stretch_initial_y = icon->y;
7058 	container->details->stretch_initial_size = initial_size;
7059 
7060 	emit_stretch_started (container, icon);
7061 }
7062 
7063 /**
7064  * nautilus_canvas_container_has_stretch_handles
7065  * @container: An canvas container widget.
7066  * 
7067  * Returns true if the first selected item has stretch handles.
7068  **/
7069 gboolean
7070 nautilus_canvas_container_has_stretch_handles (NautilusCanvasContainer *container)
7071 {
7072 	NautilusCanvasIcon *icon;
7073 
7074 	icon = get_first_selected_icon (container);
7075 	if (icon == NULL) {
7076 		return FALSE;
7077 	}
7078 
7079 	return icon == container->details->stretch_icon;
7080 }
7081 
7082 /**
7083  * nautilus_canvas_container_is_stretched
7084  * @container: An canvas container widget.
7085  * 
7086  * Returns true if the any selected item is stretched to a size other than 1.0.
7087  **/
7088 gboolean
7089 nautilus_canvas_container_is_stretched (NautilusCanvasContainer *container)
7090 {
7091 	GList *p;
7092 	NautilusCanvasIcon *icon;
7093 
7094 	for (p = container->details->icons; p != NULL; p = p->next) {
7095 		icon = p->data;
7096 		if (icon->is_selected && icon->scale != 1.0) {
7097 			return TRUE;
7098 		}
7099 	}
7100 	return FALSE;
7101 }
7102 
7103 /**
7104  * nautilus_canvas_container_unstretch
7105  * @container: An canvas container widget.
7106  * 
7107  * Gets rid of any canvas stretching.
7108  **/
7109 void
7110 nautilus_canvas_container_unstretch (NautilusCanvasContainer *container)
7111 {
7112 	GList *p;
7113 	NautilusCanvasIcon *icon;
7114 
7115 	for (p = container->details->icons; p != NULL; p = p->next) {
7116 		icon = p->data;
7117 		if (icon->is_selected) {
7118 			nautilus_canvas_container_move_icon (container, icon,
7119 							       icon->x, icon->y,
7120 							       1.0,
7121 							       FALSE, TRUE, TRUE);
7122 		}
7123 	}
7124 }
7125 
7126 static void
7127 compute_stretch (StretchState *start,
7128 		 StretchState *current)
7129 {
7130 	gboolean right, bottom;
7131 	int x_stretch, y_stretch;
7132 
7133 	/* FIXME bugzilla.gnome.org 45390: This doesn't correspond to
7134          * the way the handles are drawn.
7135 	 */
7136 	/* Figure out which handle we are dragging. */
7137 	right = start->pointer_x > start->icon_x + (int) start->icon_size / 2;
7138 	bottom = start->pointer_y > start->icon_y + (int) start->icon_size / 2;
7139 
7140 	/* Figure out how big we should stretch. */
7141 	x_stretch = start->pointer_x - current->pointer_x;
7142 	y_stretch = start->pointer_y - current->pointer_y;
7143 	if (right) {
7144 		x_stretch = - x_stretch;
7145 	}
7146 	if (bottom) {
7147 		y_stretch = - y_stretch;
7148 	}
7149 	current->icon_size = MAX ((int) start->icon_size + MIN (x_stretch, y_stretch),
7150 				    (int) NAUTILUS_ICON_SIZE_SMALLEST);
7151 
7152 	/* Figure out where the corner of the icon should be. */
7153 	current->icon_x = start->icon_x;
7154 	if (!right) {
7155 		current->icon_x += start->icon_size - current->icon_size;
7156 	}
7157 	current->icon_y = start->icon_y;
7158 	if (!bottom) {
7159 		current->icon_y += start->icon_size - current->icon_size;
7160 	}
7161 }
7162 
7163 char *
7164 nautilus_canvas_container_get_icon_uri (NautilusCanvasContainer *container,
7165 					  NautilusCanvasIcon *icon)
7166 {
7167 	char *uri;
7168 
7169 	uri = NULL;
7170 	g_signal_emit (container,
7171 		       signals[GET_ICON_URI], 0,
7172 		       icon->data,
7173 		       &uri);
7174 	return uri;
7175 }
7176 
7177 char *
7178 nautilus_canvas_container_get_icon_drop_target_uri (NautilusCanvasContainer *container,
7179 						      NautilusCanvasIcon *icon)
7180 {
7181 	char *uri;
7182 
7183 	uri = NULL;
7184 	g_signal_emit (container,
7185 		       signals[GET_ICON_DROP_TARGET_URI], 0,
7186 		       icon->data,
7187 		       &uri);
7188 	return uri;
7189 }
7190 
7191 /* Call to reset the scroll region only if the container is not empty,
7192  * to avoid having the flag linger until the next file is added.
7193  */
7194 static void
7195 reset_scroll_region_if_not_empty (NautilusCanvasContainer *container)
7196 {
7197 	if (!nautilus_canvas_container_is_empty (container)) {
7198 		nautilus_canvas_container_reset_scroll_region (container);
7199 	}
7200 }
7201 
7202 /* Switch from automatic layout to manual or vice versa.
7203  * If we switch to manual layout, we restore the icon positions from the
7204  * last manual layout.
7205  */
7206 void
7207 nautilus_canvas_container_set_auto_layout (NautilusCanvasContainer *container,
7208 					   gboolean auto_layout)
7209 {
7210 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7211 	g_return_if_fail (auto_layout == FALSE || auto_layout == TRUE);
7212 
7213 	if (container->details->auto_layout == auto_layout) {
7214 		return;
7215 	}
7216 
7217 	reset_scroll_region_if_not_empty (container);
7218 	container->details->auto_layout = auto_layout;
7219 
7220 	if (!auto_layout) {
7221 		reload_icon_positions (container);
7222 		nautilus_canvas_container_freeze_icon_positions (container);
7223 	}
7224 
7225 	container->details->needs_resort = TRUE;
7226 	redo_layout (container);
7227 
7228 	g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
7229 }
7230 
7231 gboolean
7232 nautilus_canvas_container_is_keep_aligned (NautilusCanvasContainer *container)
7233 {
7234 	return container->details->keep_aligned;
7235 }
7236 
7237 static gboolean
7238 align_icons_callback (gpointer callback_data)
7239 {
7240 	NautilusCanvasContainer *container;
7241 
7242 	container = NAUTILUS_CANVAS_CONTAINER (callback_data);
7243 	align_icons (container);
7244 	container->details->align_idle_id = 0;
7245 
7246 	return FALSE;
7247 }
7248 
7249 static void
7250 unschedule_align_icons (NautilusCanvasContainer *container)
7251 {
7252         if (container->details->align_idle_id != 0) {
7253 		g_source_remove (container->details->align_idle_id);
7254 		container->details->align_idle_id = 0;
7255 	}
7256 }
7257 
7258 static void
7259 schedule_align_icons (NautilusCanvasContainer *container)
7260 {
7261 	if (container->details->align_idle_id == 0
7262 	    && container->details->has_been_allocated) {
7263 		container->details->align_idle_id = g_idle_add
7264 			(align_icons_callback, container);
7265 	}
7266 }
7267 
7268 void
7269 nautilus_canvas_container_set_keep_aligned (NautilusCanvasContainer *container,
7270 					    gboolean keep_aligned)
7271 {
7272 	if (container->details->keep_aligned != keep_aligned) {
7273 		container->details->keep_aligned = keep_aligned;
7274 		
7275 		if (keep_aligned && !container->details->auto_layout) {
7276 			schedule_align_icons (container);
7277 		} else {
7278 			unschedule_align_icons (container);
7279 		}
7280 	}
7281 }
7282 
7283 void
7284 nautilus_canvas_container_set_layout_mode (NautilusCanvasContainer *container,
7285 					   NautilusCanvasLayoutMode mode)
7286 {
7287 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7288 
7289 	container->details->layout_mode = mode;
7290 	invalidate_labels (container);
7291 
7292 	container->details->needs_resort = TRUE;
7293 	redo_layout (container);
7294 
7295 	g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
7296 }
7297 
7298 void
7299 nautilus_canvas_container_set_label_position (NautilusCanvasContainer *container,
7300 					      NautilusCanvasLabelPosition position)
7301 {
7302 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7303 
7304 	if (container->details->label_position != position) {
7305 		container->details->label_position = position;
7306 
7307 		invalidate_labels (container);
7308 		nautilus_canvas_container_request_update_all (container);
7309 
7310 		schedule_redo_layout (container);
7311 	}
7312 }
7313 
7314 /* Switch from automatic to manual layout, freezing all the icons in their
7315  * current positions instead of restoring canvas positions from the last manual
7316  * layout as set_auto_layout does.
7317  */
7318 void
7319 nautilus_canvas_container_freeze_icon_positions (NautilusCanvasContainer *container)
7320 {
7321 	gboolean changed;
7322 	GList *p;
7323 	NautilusCanvasIcon *icon;
7324 	NautilusCanvasPosition position;
7325 
7326 	changed = container->details->auto_layout;
7327 	container->details->auto_layout = FALSE;
7328 	
7329 	for (p = container->details->icons; p != NULL; p = p->next) {
7330 		icon = p->data;
7331 
7332 		position.x = icon->saved_ltr_x;
7333 		position.y = icon->y;
7334 		position.scale = icon->scale;
7335 		g_signal_emit (container, signals[ICON_POSITION_CHANGED], 0,
7336 			       icon->data, &position);
7337 	}
7338 
7339 	if (changed) {
7340 		g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
7341 	}
7342 }
7343 
7344 /* Re-sort, switching to automatic layout if it was in manual layout. */
7345 void
7346 nautilus_canvas_container_sort (NautilusCanvasContainer *container)
7347 {
7348 	gboolean changed;
7349 
7350 	changed = !container->details->auto_layout;
7351 	container->details->auto_layout = TRUE;
7352 
7353 	reset_scroll_region_if_not_empty (container);
7354 	container->details->needs_resort = TRUE;
7355 	redo_layout (container);
7356 
7357 	if (changed) {
7358 		g_signal_emit (container, signals[LAYOUT_CHANGED], 0);
7359 	}
7360 }
7361 
7362 gboolean
7363 nautilus_canvas_container_is_auto_layout (NautilusCanvasContainer *container)
7364 {
7365 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
7366 
7367 	return container->details->auto_layout;
7368 }
7369 
7370 static void
7371 pending_icon_to_rename_destroy_callback (NautilusCanvasItem *item, NautilusCanvasContainer *container)
7372 {
7373 	g_assert (container->details->pending_icon_to_rename != NULL);
7374 	g_assert (container->details->pending_icon_to_rename->item == item);
7375 	container->details->pending_icon_to_rename = NULL;
7376 }
7377 
7378 static NautilusCanvasIcon *
7379 get_pending_icon_to_rename (NautilusCanvasContainer *container)
7380 {
7381 	return container->details->pending_icon_to_rename;
7382 }
7383 
7384 static void
7385 set_pending_icon_to_rename (NautilusCanvasContainer *container, NautilusCanvasIcon *icon)
7386 {
7387 	NautilusCanvasIcon *old_icon;
7388 	
7389 	old_icon = container->details->pending_icon_to_rename;
7390 	
7391 	if (icon == old_icon) {
7392 		return;
7393 	}
7394 	
7395 	if (old_icon != NULL) {
7396 		g_signal_handlers_disconnect_by_func
7397 			(old_icon->item,
7398 			 G_CALLBACK (pending_icon_to_rename_destroy_callback),
7399 			 container);
7400 	}
7401 	
7402 	if (icon != NULL) {
7403 		g_signal_connect (icon->item, "destroy",
7404 				  G_CALLBACK (pending_icon_to_rename_destroy_callback), container);
7405 	}
7406 	
7407 	container->details->pending_icon_to_rename = icon;
7408 }
7409 
7410 static void
7411 process_pending_icon_to_rename (NautilusCanvasContainer *container)
7412 {
7413 	NautilusCanvasIcon *pending_icon_to_rename;
7414 	
7415 	pending_icon_to_rename = get_pending_icon_to_rename (container);
7416 	
7417 	if (pending_icon_to_rename != NULL) {
7418 		if (pending_icon_to_rename->is_selected && !has_multiple_selection (container)) {
7419 			nautilus_canvas_container_start_renaming_selected_item (container, FALSE);
7420 		} else {
7421 			set_pending_icon_to_rename (container, NULL);
7422 		}
7423 	}
7424 }
7425 
7426 static gboolean
7427 is_renaming_pending (NautilusCanvasContainer *container)
7428 {
7429 	return get_pending_icon_to_rename (container) != NULL;
7430 }
7431 
7432 static gboolean
7433 is_renaming (NautilusCanvasContainer *container)
7434 {
7435 	return container->details->renaming;
7436 }
7437 
7438 /**
7439  * nautilus_canvas_container_start_renaming_selected_item
7440  * @container: An canvas container widget.
7441  * @select_all: Whether the whole file should initially be selected, or
7442  *              only its basename (i.e. everything except its extension).
7443  * 
7444  * Displays the edit name widget on the first selected icon
7445  **/
7446 void
7447 nautilus_canvas_container_start_renaming_selected_item (NautilusCanvasContainer *container,
7448 							gboolean select_all)
7449 {
7450 	NautilusCanvasContainerDetails *details;
7451 	NautilusCanvasIcon *icon;
7452 	EelDRect icon_rect;
7453 	PangoContext *context;
7454 	PangoFontDescription *desc;
7455 	const char *editable_text;
7456 	int x, y, width;
7457 	int start_offset, end_offset;
7458 
7459 	/* Check if it already in renaming mode, if so - select all */
7460 	details = container->details;
7461 	if (details->renaming) {
7462 		eel_editable_label_select_region (EEL_EDITABLE_LABEL (details->rename_widget),
7463 						  0,
7464 						  -1);
7465 		return;
7466 	}
7467 
7468 	/* Find selected icon */
7469 	icon = get_first_selected_icon (container);
7470 	if (icon == NULL) {
7471 		return;
7472 	}
7473 
7474 	g_assert (!has_multiple_selection (container));
7475 
7476 
7477 	if (!icon_is_positioned (icon)) {
7478 		set_pending_icon_to_rename (container, icon);
7479 		return;
7480 	}
7481 	
7482 	set_pending_icon_to_rename (container, NULL);
7483 
7484 	/* Make a copy of the original editable text for a later compare */
7485 	editable_text = nautilus_canvas_item_get_editable_text (icon->item);
7486 
7487 	/* This could conceivably be NULL if a rename was triggered really early. */
7488 	if (editable_text == NULL) {
7489 		return;
7490 	}
7491 
7492 	details->original_text = g_strdup (editable_text);
7493 	
7494 	/* Freeze updates so files added while renaming don't cause rename to loose focus, bug #318373 */
7495 	nautilus_canvas_container_freeze_updates (container);
7496 
7497 	/* Create text renaming widget, if it hasn't been created already.
7498 	 * We deal with the broken canvas text item widget by keeping it around
7499 	 * so its contents can still be cut and pasted as part of the clipboard
7500 	 */
7501 	if (details->rename_widget == NULL) {
7502 		details->rename_widget = eel_editable_label_new ("Test text");
7503 		eel_editable_label_set_line_wrap (EEL_EDITABLE_LABEL (details->rename_widget), TRUE);
7504 		eel_editable_label_set_line_wrap_mode (EEL_EDITABLE_LABEL (details->rename_widget), PANGO_WRAP_WORD_CHAR);
7505 		eel_editable_label_set_draw_outline (EEL_EDITABLE_LABEL (details->rename_widget), TRUE);
7506 
7507 		eel_editable_label_set_justify (EEL_EDITABLE_LABEL (details->rename_widget), GTK_JUSTIFY_CENTER);
7508 
7509 		gtk_misc_set_padding (GTK_MISC (details->rename_widget), 1, 1);
7510 		gtk_layout_put (GTK_LAYOUT (container),
7511 				details->rename_widget, 0, 0);
7512 	} 
7513 
7514 	/* Set the right font */
7515 	if (details->font) {
7516 		desc = pango_font_description_from_string (details->font);
7517 	} else {
7518 		context = gtk_widget_get_pango_context (GTK_WIDGET (container));
7519 		desc = pango_font_description_copy (pango_context_get_font_description (context));
7520 	}
7521 	eel_editable_label_set_font_description (EEL_EDITABLE_LABEL (details->rename_widget),
7522 						 desc);
7523 	pango_font_description_free (desc);
7524 	
7525 	icon_rect = nautilus_canvas_item_get_icon_rectangle (icon->item);
7526 
7527 	width = nautilus_canvas_item_get_max_text_width (icon->item);
7528 
7529 	eel_canvas_w2c (EEL_CANVAS_ITEM (icon->item)->canvas,
7530 			(icon_rect.x0 + icon_rect.x1) / 2,
7531 			icon_rect.y1,
7532 			&x, &y);
7533 	x = x - width / 2 - 1;
7534 
7535 	gtk_layout_move (GTK_LAYOUT (container),
7536 			 details->rename_widget,
7537 			 x, y);
7538 	
7539 	gtk_widget_set_size_request (details->rename_widget,
7540 				     width, -1);
7541 	eel_editable_label_set_text (EEL_EDITABLE_LABEL (details->rename_widget),
7542 				     editable_text);
7543 	if (select_all) {
7544 		start_offset = 0;
7545 		end_offset = -1;
7546 	} else {
7547 		eel_filename_get_rename_region (editable_text, &start_offset, &end_offset);
7548 	}
7549 
7550 	gtk_widget_show (details->rename_widget);
7551 	gtk_widget_grab_focus (details->rename_widget);
7552 
7553 	eel_editable_label_select_region (EEL_EDITABLE_LABEL (details->rename_widget),
7554 					  start_offset,
7555 					  end_offset);
7556 	
7557 	g_signal_emit (container,
7558 		       signals[ICON_RENAME_STARTED], 0,
7559 		       GTK_EDITABLE (details->rename_widget));
7560 	
7561 	nautilus_canvas_container_update_icon (container, icon);
7562 	
7563 	/* We are in renaming mode */
7564 	details->renaming = TRUE;
7565 	nautilus_canvas_item_set_renaming (icon->item, TRUE);
7566 }
7567 
7568 static void
7569 end_renaming_mode (NautilusCanvasContainer *container, gboolean commit)
7570 {
7571 	NautilusCanvasIcon *icon;
7572 	const char *changed_text = NULL;
7573 
7574 	set_pending_icon_to_rename (container, NULL);
7575 
7576 	icon = get_icon_being_renamed (container);
7577 	if (icon == NULL) {
7578 		return;
7579 	}
7580 
7581 	/* We are not in renaming mode */
7582 	container->details->renaming = FALSE;
7583 	nautilus_canvas_item_set_renaming (icon->item, FALSE);
7584 	
7585 	nautilus_canvas_container_unfreeze_updates (container);
7586 
7587 	if (commit) {
7588 		set_pending_icon_to_reveal (container, icon);
7589 	}
7590 
7591 	gtk_widget_grab_focus (GTK_WIDGET (container));
7592 	
7593 	if (commit) {
7594 		/* Verify that text has been modified before signalling change. */			
7595 		changed_text = eel_editable_label_get_text (EEL_EDITABLE_LABEL (container->details->rename_widget));
7596 		if (strcmp (container->details->original_text, changed_text) == 0) {
7597 			changed_text = NULL;
7598 		}
7599 	}
7600 
7601 	g_signal_emit (container,
7602 		       signals[ICON_RENAME_ENDED], 0,
7603 		       icon->data,		       changed_text);
7604 
7605 	gtk_widget_hide (container->details->rename_widget);
7606 	g_free (container->details->original_text);
7607 }
7608 
7609 gboolean
7610 nautilus_canvas_container_has_stored_icon_positions (NautilusCanvasContainer *container)
7611 {
7612 	GList *p;
7613 	NautilusCanvasIcon *icon;
7614 	gboolean have_stored_position;
7615 	NautilusCanvasPosition position;
7616 
7617 	for (p = container->details->icons; p != NULL; p = p->next) {
7618 		icon = p->data;
7619 
7620 		have_stored_position = FALSE;
7621 		g_signal_emit (container,
7622 			       signals[GET_STORED_ICON_POSITION], 0,
7623 			       icon->data,
7624 			       &position,
7625 			       &have_stored_position);
7626 		if (have_stored_position) {
7627 			return TRUE;
7628 		}
7629 	}
7630 	return FALSE;
7631 }
7632 
7633 void
7634 nautilus_canvas_container_set_single_click_mode (NautilusCanvasContainer *container,
7635 						 gboolean single_click_mode)
7636 {
7637 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7638 
7639 	container->details->single_click_mode = single_click_mode;
7640 }
7641 
7642 /* Return if the canvas container is a fixed size */
7643 gboolean
7644 nautilus_canvas_container_get_is_fixed_size (NautilusCanvasContainer *container)
7645 {
7646 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
7647 
7648 	return container->details->is_fixed_size;
7649 }
7650 
7651 /* Set the canvas container to be a fixed size */
7652 void
7653 nautilus_canvas_container_set_is_fixed_size (NautilusCanvasContainer *container,
7654 					     gboolean is_fixed_size)
7655 {
7656 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7657 
7658 	container->details->is_fixed_size = is_fixed_size;
7659 }
7660 
7661 gboolean
7662 nautilus_canvas_container_get_is_desktop (NautilusCanvasContainer *container)
7663 {
7664 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
7665 
7666 	return container->details->is_desktop;
7667 }
7668 
7669 void
7670 nautilus_canvas_container_set_is_desktop (NautilusCanvasContainer *container,
7671 					  gboolean is_desktop)
7672 {
7673 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7674 
7675 	container->details->is_desktop = is_desktop;
7676 
7677 	if (is_desktop) {
7678 		GtkStyleContext *context;
7679 
7680 		context = gtk_widget_get_style_context (GTK_WIDGET (container));
7681 		gtk_style_context_add_class (context, "nautilus-desktop");
7682 	}
7683 }
7684 
7685 void
7686 nautilus_canvas_container_set_margins (NautilusCanvasContainer *container,
7687 				       int left_margin,
7688 				       int right_margin,
7689 				       int top_margin,
7690 				       int bottom_margin)
7691 {
7692 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7693 
7694 	container->details->left_margin = left_margin;
7695 	container->details->right_margin = right_margin;
7696 	container->details->top_margin = top_margin;
7697 	container->details->bottom_margin = bottom_margin;
7698 
7699 	/* redo layout of icons as the margins have changed */
7700 	schedule_redo_layout (container);
7701 }
7702 
7703 void
7704 nautilus_canvas_container_set_use_drop_shadows (NautilusCanvasContainer  *container,
7705 						gboolean                use_drop_shadows)
7706 {
7707 	if (container->details->drop_shadows_requested == use_drop_shadows) {
7708 		return;
7709 	}
7710 
7711 	container->details->drop_shadows_requested = use_drop_shadows;
7712 	container->details->use_drop_shadows = use_drop_shadows;
7713 	gtk_widget_queue_draw (GTK_WIDGET (container));
7714 }
7715 
7716 /* handle theme changes */
7717 
7718 void
7719 nautilus_canvas_container_set_font (NautilusCanvasContainer *container,
7720 				    const char *font)
7721 {
7722 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7723 
7724 	if (g_strcmp0 (container->details->font, font) == 0) {
7725 		return;
7726 	}
7727 
7728 	g_free (container->details->font);
7729 	container->details->font = g_strdup (font);
7730 
7731 	invalidate_labels (container);
7732 	nautilus_canvas_container_request_update_all (container);
7733 	gtk_widget_queue_draw (GTK_WIDGET (container));
7734 }
7735 
7736 /**
7737  * nautilus_canvas_container_get_icon_description
7738  * @container: An canvas container widget.
7739  * @data: Icon data 
7740  * 
7741  * Gets the description for the icon. This function may return NULL.
7742  **/
7743 char*
7744 nautilus_canvas_container_get_icon_description (NautilusCanvasContainer *container,
7745 						  NautilusCanvasIconData      *data)
7746 {
7747 	NautilusCanvasContainerClass *klass;
7748 
7749 	klass = NAUTILUS_CANVAS_CONTAINER_GET_CLASS (container);
7750 
7751 	if (klass->get_icon_description) {
7752 		return klass->get_icon_description (container, data);
7753 	} else {
7754 		return NULL;
7755 	}
7756 }
7757 
7758 gboolean
7759 nautilus_canvas_container_get_allow_moves (NautilusCanvasContainer *container)
7760 {
7761 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
7762 
7763 	return container->details->drag_allow_moves;
7764 }
7765 
7766 void
7767 nautilus_canvas_container_set_allow_moves	(NautilusCanvasContainer *container,
7768 						 gboolean               allow_moves)
7769 {
7770 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7771 
7772 	container->details->drag_allow_moves = allow_moves;
7773 }
7774 
7775 /**
7776  * nautilus_canvas_container_set_highlighted_for_clipboard
7777  * @container: An canvas container widget.
7778  * @data: Canvas Data associated with all icons that should be highlighted.
7779  *        Others will be unhighlighted.
7780  **/
7781 void
7782 nautilus_canvas_container_set_highlighted_for_clipboard (NautilusCanvasContainer *container,
7783 							 GList                 *clipboard_canvas_data)
7784 {
7785 	GList *l;
7786 	NautilusCanvasIcon *icon;
7787 	gboolean highlighted_for_clipboard;
7788 
7789 	g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container));
7790 
7791 	for (l = container->details->icons; l != NULL; l = l->next) {
7792 		icon = l->data;
7793 		highlighted_for_clipboard = (g_list_find (clipboard_canvas_data, icon->data) != NULL);
7794 
7795 		eel_canvas_item_set (EEL_CANVAS_ITEM (icon->item),
7796 				     "highlighted-for-clipboard", highlighted_for_clipboard,
7797 				     NULL);
7798 	}
7799 
7800 }
7801 
7802 /* NautilusCanvasContainerAccessible */
7803 typedef struct {
7804 	EelCanvasAccessible parent;
7805 	NautilusCanvasContainerAccessiblePrivate *priv;
7806 } NautilusCanvasContainerAccessible;
7807 
7808 typedef EelCanvasAccessibleClass NautilusCanvasContainerAccessibleClass;
7809 
7810 #define GET_ACCESSIBLE_PRIV(o) ((NautilusCanvasContainerAccessible *) o)->priv
7811 
7812 /* AtkAction interface */
7813 static gboolean
7814 nautilus_canvas_container_accessible_do_action (AtkAction *accessible, int i)
7815 {
7816 	GtkWidget *widget;
7817 	NautilusCanvasContainer *container;
7818 	GList *selection;
7819 
7820 	g_return_val_if_fail (i < LAST_ACTION, FALSE);
7821 
7822 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
7823 	if (!widget) {
7824 		return FALSE;
7825 	}
7826 	
7827 	container = NAUTILUS_CANVAS_CONTAINER (widget);
7828 	switch (i) {
7829 	case ACTION_ACTIVATE :
7830 		selection = nautilus_canvas_container_get_selection (container);
7831 
7832 		if (selection) {
7833 			g_signal_emit_by_name (container, "activate", selection);
7834 			g_list_free (selection);
7835 		}
7836 		break;
7837 	case ACTION_MENU :
7838 		handle_popups (container, NULL,"context_click_background");
7839 		break;
7840 	default :
7841 		g_warning ("Invalid action passed to NautilusCanvasContainerAccessible::do_action");
7842 		return FALSE;
7843 	}
7844 	return TRUE;
7845 }
7846 
7847 static int
7848 nautilus_canvas_container_accessible_get_n_actions (AtkAction *accessible)
7849 {
7850 	return LAST_ACTION;
7851 }
7852 
7853 static const char *
7854 nautilus_canvas_container_accessible_action_get_description (AtkAction *accessible, 
7855 							     int i)
7856 {
7857 	NautilusCanvasContainerAccessiblePrivate *priv;
7858 	
7859 	g_assert (i < LAST_ACTION);
7860 
7861 	priv = GET_ACCESSIBLE_PRIV (accessible);
7862 	
7863 	if (priv->action_descriptions[i]) {
7864 		return priv->action_descriptions[i];
7865 	} else {
7866 		return nautilus_canvas_container_accessible_action_descriptions[i];
7867 	}
7868 }
7869 
7870 static const char *
7871 nautilus_canvas_container_accessible_action_get_name (AtkAction *accessible, int i)
7872 {
7873 	g_assert (i < LAST_ACTION);
7874 
7875 	return nautilus_canvas_container_accessible_action_names[i];
7876 }
7877 
7878 static const char *
7879 nautilus_canvas_container_accessible_action_get_keybinding (AtkAction *accessible, 
7880 							    int i)
7881 {
7882 	g_assert (i < LAST_ACTION);
7883 
7884 	return NULL;
7885 }
7886 
7887 static gboolean
7888 nautilus_canvas_container_accessible_action_set_description (AtkAction *accessible, 
7889 							     int i, 
7890 							     const char *description)
7891 {
7892 	NautilusCanvasContainerAccessiblePrivate *priv;
7893 
7894 	g_assert (i < LAST_ACTION);
7895 
7896 	priv = GET_ACCESSIBLE_PRIV (accessible);
7897 
7898 	if (priv->action_descriptions[i]) {
7899 		g_free (priv->action_descriptions[i]);
7900 	}
7901 	priv->action_descriptions[i] = g_strdup (description);
7902 
7903 	return FALSE;
7904 }
7905 
7906 static void
7907 nautilus_canvas_container_accessible_action_interface_init (AtkActionIface *iface)
7908 {
7909 	iface->do_action = nautilus_canvas_container_accessible_do_action;
7910 	iface->get_n_actions = nautilus_canvas_container_accessible_get_n_actions;
7911 	iface->get_description = nautilus_canvas_container_accessible_action_get_description;
7912 	iface->get_name = nautilus_canvas_container_accessible_action_get_name;
7913 	iface->get_keybinding = nautilus_canvas_container_accessible_action_get_keybinding;
7914 	iface->set_description = nautilus_canvas_container_accessible_action_set_description;
7915 }
7916 
7917 /* AtkSelection interface */
7918 
7919 static void
7920 nautilus_canvas_container_accessible_update_selection (AtkObject *accessible)
7921 {
7922 	NautilusCanvasContainer *container;
7923 	NautilusCanvasContainerAccessiblePrivate *priv;
7924 	GList *l;
7925 	NautilusCanvasIcon *icon;
7926 
7927 	container = NAUTILUS_CANVAS_CONTAINER (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
7928 	priv = GET_ACCESSIBLE_PRIV (accessible);
7929 
7930 	if (priv->selection) {
7931 		g_list_free (priv->selection);
7932 		priv->selection = NULL;
7933 	}
7934 	
7935 	for (l = container->details->icons; l != NULL; l = l->next) {
7936 		icon = l->data;
7937 		if (icon->is_selected) {
7938 			priv->selection = g_list_prepend (priv->selection, 
7939 							  icon);
7940 		}
7941 	}
7942 
7943 	priv->selection = g_list_reverse (priv->selection);
7944 }
7945 
7946 static void
7947 nautilus_canvas_container_accessible_selection_changed_cb (NautilusCanvasContainer *container,
7948 							   gpointer data)
7949 {
7950 	g_signal_emit_by_name (data, "selection_changed");
7951 }
7952 
7953 static void
7954 nautilus_canvas_container_accessible_icon_added_cb (NautilusCanvasContainer *container,
7955 						      NautilusCanvasIconData *icon_data,
7956 						      gpointer data)
7957 {
7958 	NautilusCanvasIcon *icon;
7959 	AtkObject *atk_parent;
7960 	AtkObject *atk_child;
7961 	int index;
7962 
7963 	icon = g_hash_table_lookup (container->details->icon_set, icon_data);
7964 	if (icon) {
7965 		atk_parent = ATK_OBJECT (data);
7966 		atk_child = atk_gobject_accessible_for_object 
7967 			(G_OBJECT (icon->item));
7968 		index = g_list_index (container->details->icons, icon);
7969 		
7970 		g_signal_emit_by_name (atk_parent, "children_changed::add",
7971 				       index, atk_child, NULL);
7972 	}
7973 }
7974 
7975 static void
7976 nautilus_canvas_container_accessible_icon_removed_cb (NautilusCanvasContainer *container,
7977 							NautilusCanvasIconData *icon_data,
7978 							gpointer data)
7979 {
7980 	NautilusCanvasIcon *icon;
7981 	AtkObject *atk_parent;
7982 	AtkObject *atk_child;
7983 	int index;
7984 	
7985 	icon = g_hash_table_lookup (container->details->icon_set, icon_data);
7986 	if (icon) {
7987 		atk_parent = ATK_OBJECT (data);
7988 		atk_child = atk_gobject_accessible_for_object 
7989 			(G_OBJECT (icon->item));
7990 		index = g_list_index (container->details->icons, icon);
7991 		
7992 		g_signal_emit_by_name (atk_parent, "children_changed::remove",
7993 				       index, atk_child, NULL);
7994 	}
7995 }
7996 
7997 static void
7998 nautilus_canvas_container_accessible_cleared_cb (NautilusCanvasContainer *container, 
7999 						 gpointer data)
8000 {
8001 	g_signal_emit_by_name (data, "children_changed", 0, NULL, NULL);
8002 }
8003 
8004 static gboolean 
8005 nautilus_canvas_container_accessible_add_selection (AtkSelection *accessible, 
8006 						    int i)
8007 {
8008 	GtkWidget *widget;
8009 	NautilusCanvasContainer *container;
8010 	GList *l;
8011 	GList *selection;
8012 	NautilusCanvasIcon *icon;
8013 
8014 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8015 	if (!widget) {
8016 		return FALSE;
8017 	}
8018 
8019         container = NAUTILUS_CANVAS_CONTAINER (widget);
8020 	
8021 	l = g_list_nth (container->details->icons, i);
8022 	if (l) {
8023 		icon = l->data;
8024 		
8025 		selection = nautilus_canvas_container_get_selection (container);
8026 		selection = g_list_prepend (selection, 
8027 					    icon->data);
8028 		nautilus_canvas_container_set_selection (container, selection);
8029 		
8030 		g_list_free (selection);
8031 		return TRUE;
8032 	}
8033 
8034 	return FALSE;
8035 }
8036 
8037 static gboolean
8038 nautilus_canvas_container_accessible_clear_selection (AtkSelection *accessible)
8039 {
8040 	GtkWidget *widget;
8041 	NautilusCanvasContainer *container;
8042 
8043 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8044 	if (!widget) {
8045 		return FALSE;
8046 	}
8047 
8048         container = NAUTILUS_CANVAS_CONTAINER (widget);
8049 
8050 	nautilus_canvas_container_unselect_all (container);
8051 
8052 	return TRUE;
8053 }
8054 
8055 static AtkObject *
8056 nautilus_canvas_container_accessible_ref_selection (AtkSelection *accessible, 
8057 						    int i)
8058 {
8059 	NautilusCanvasContainerAccessiblePrivate *priv;
8060 	AtkObject *atk_object;
8061 	GList *item;
8062 	NautilusCanvasIcon *icon;
8063 
8064 	nautilus_canvas_container_accessible_update_selection (ATK_OBJECT (accessible));
8065 	priv = GET_ACCESSIBLE_PRIV (accessible);
8066 
8067 	item = (g_list_nth (priv->selection, i));
8068 
8069 	if (item) {
8070 		icon = item->data;
8071 		atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item));
8072 		if (atk_object) {
8073 			g_object_ref (atk_object);
8074 		}
8075 
8076 		return atk_object;
8077 	} else {
8078 		return NULL;
8079 	}
8080 }
8081 
8082 static int
8083 nautilus_canvas_container_accessible_get_selection_count (AtkSelection *accessible)
8084 {
8085 	NautilusCanvasContainerAccessiblePrivate *priv;
8086 	int count;
8087 
8088 	priv = GET_ACCESSIBLE_PRIV (accessible);
8089 	nautilus_canvas_container_accessible_update_selection (ATK_OBJECT (accessible));
8090 	count = g_list_length (priv->selection);
8091 
8092 	return count;
8093 }
8094 
8095 static gboolean
8096 nautilus_canvas_container_accessible_is_child_selected (AtkSelection *accessible,
8097 							int i)
8098 {
8099 	NautilusCanvasContainer *container;
8100 	GList *l;
8101 	NautilusCanvasIcon *icon;
8102 	GtkWidget *widget;
8103 
8104 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8105 	if (!widget) {
8106 		return FALSE;
8107 	}
8108 
8109         container = NAUTILUS_CANVAS_CONTAINER (widget);
8110 
8111 	l = g_list_nth (container->details->icons, i);
8112 	if (l) {
8113 		icon = l->data;
8114 		return icon->is_selected;
8115 	}
8116 	return FALSE;
8117 }
8118 
8119 static gboolean
8120 nautilus_canvas_container_accessible_remove_selection (AtkSelection *accessible,
8121 						       int i)
8122 {
8123 	NautilusCanvasContainerAccessiblePrivate *priv;
8124 	NautilusCanvasContainer *container;
8125 	GList *l;
8126 	GList *selection;
8127 	NautilusCanvasIcon *icon;
8128 	GtkWidget *widget;
8129 
8130 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8131 	if (!widget) {
8132 		return FALSE;
8133 	}
8134 
8135         container = NAUTILUS_CANVAS_CONTAINER (widget);
8136 	nautilus_canvas_container_accessible_update_selection (ATK_OBJECT (accessible));
8137 
8138 	priv = GET_ACCESSIBLE_PRIV (accessible);
8139 	l = g_list_nth (priv->selection, i);
8140 	if (l) {
8141 		icon = l->data;
8142 		
8143 		selection = nautilus_canvas_container_get_selection (container);
8144 		selection = g_list_remove (selection, icon->data);
8145 		nautilus_canvas_container_set_selection (container, selection);
8146 		
8147 		g_list_free (selection);
8148 		return TRUE;
8149 	}
8150 
8151 	return FALSE;	
8152 }
8153 
8154 static gboolean
8155 nautilus_canvas_container_accessible_select_all_selection (AtkSelection *accessible)
8156 {
8157 	NautilusCanvasContainer *container;
8158 	GtkWidget *widget;
8159 
8160 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8161 	if (!widget) {
8162 		return FALSE;
8163 	}
8164 
8165         container = NAUTILUS_CANVAS_CONTAINER (widget);
8166 
8167 	nautilus_canvas_container_select_all (container);
8168 
8169 	return TRUE;
8170 }
8171 
8172 void
8173 nautilus_canvas_container_widget_to_file_operation_position (NautilusCanvasContainer *container,
8174 							     GdkPoint              *position)
8175 {
8176 	double x, y;
8177 
8178 	g_return_if_fail (position != NULL);
8179 
8180 	x = position->x;
8181 	y = position->y;
8182 
8183 	eel_canvas_window_to_world (EEL_CANVAS (container), x, y, &x, &y);
8184 
8185 	position->x = (int) x;
8186 	position->y = (int) y;
8187 
8188 	/* ensure that we end up in the middle of the icon */
8189 	position->x -= nautilus_get_icon_size_for_zoom_level (container->details->zoom_level) / 2;
8190 	position->y -= nautilus_get_icon_size_for_zoom_level (container->details->zoom_level) / 2;
8191 }
8192 
8193 static void 
8194 nautilus_canvas_container_accessible_selection_interface_init (AtkSelectionIface *iface)
8195 {
8196 	iface->add_selection = nautilus_canvas_container_accessible_add_selection;
8197 	iface->clear_selection = nautilus_canvas_container_accessible_clear_selection;
8198 	iface->ref_selection = nautilus_canvas_container_accessible_ref_selection;
8199 	iface->get_selection_count = nautilus_canvas_container_accessible_get_selection_count;
8200 	iface->is_child_selected = nautilus_canvas_container_accessible_is_child_selected;
8201 	iface->remove_selection = nautilus_canvas_container_accessible_remove_selection;
8202 	iface->select_all_selection = nautilus_canvas_container_accessible_select_all_selection;
8203 }
8204 
8205 
8206 static gint 
8207 nautilus_canvas_container_accessible_get_n_children (AtkObject *accessible)
8208 {
8209 	NautilusCanvasContainer *container;
8210 	GtkWidget *widget;
8211 	gint i;
8212 	
8213 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8214 	if (!widget) {
8215 		return FALSE;
8216 	}
8217 
8218 	container = NAUTILUS_CANVAS_CONTAINER (widget);
8219 
8220 	i = g_hash_table_size (container->details->icon_set);
8221 	if (container->details->rename_widget) {
8222 		i++;
8223 	}
8224 
8225 	return i;
8226 }
8227 
8228 static AtkObject* 
8229 nautilus_canvas_container_accessible_ref_child (AtkObject *accessible, int i)
8230 {
8231         AtkObject *atk_object;
8232         NautilusCanvasContainer *container;
8233         GList *item;
8234         NautilusCanvasIcon *icon;
8235 	GtkWidget *widget;
8236         
8237 	widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
8238 	if (!widget) {
8239 		return NULL;
8240 	}
8241 
8242         container = NAUTILUS_CANVAS_CONTAINER (widget);
8243         
8244         item = (g_list_nth (container->details->icons, i));
8245         
8246         if (item) {
8247                 icon = item->data;
8248                 
8249                 atk_object = atk_gobject_accessible_for_object (G_OBJECT (icon->item));
8250                 g_object_ref (atk_object);
8251 
8252                 return atk_object;
8253         } else {
8254 		if (i == g_list_length (container->details->icons)) {
8255 			if (container->details->rename_widget) {
8256 				atk_object = gtk_widget_get_accessible (container->details->rename_widget);
8257 				g_object_ref (atk_object);
8258 
8259                 		return atk_object;
8260 			}
8261 		}
8262                 return NULL;
8263         }
8264 }
8265 
8266 static GType nautilus_canvas_container_accessible_get_type (void);
8267 
8268 G_DEFINE_TYPE_WITH_CODE (NautilusCanvasContainerAccessible, nautilus_canvas_container_accessible,
8269 			 eel_canvas_accessible_get_type (),
8270 			 G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, nautilus_canvas_container_accessible_action_interface_init)
8271 			 G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, nautilus_canvas_container_accessible_selection_interface_init))
8272 
8273 static void
8274 nautilus_canvas_container_accessible_initialize (AtkObject *accessible, 
8275 						 gpointer data)
8276 {
8277 	NautilusCanvasContainer *container;
8278 
8279 	if (ATK_OBJECT_CLASS (nautilus_canvas_container_accessible_parent_class)->initialize) {
8280 		ATK_OBJECT_CLASS (nautilus_canvas_container_accessible_parent_class)->initialize (accessible, data);
8281 	}
8282 
8283 	if (GTK_IS_ACCESSIBLE (accessible)) {
8284 		nautilus_canvas_container_accessible_update_selection 
8285 			(ATK_OBJECT (accessible));
8286 		
8287 		container = NAUTILUS_CANVAS_CONTAINER (gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)));
8288 		g_signal_connect (container, "selection_changed",
8289 				  G_CALLBACK (nautilus_canvas_container_accessible_selection_changed_cb), 
8290 				  accessible);
8291 		g_signal_connect (container, "icon_added",
8292 				  G_CALLBACK (nautilus_canvas_container_accessible_icon_added_cb), 
8293 				  accessible);
8294 		g_signal_connect (container, "icon_removed",
8295 				  G_CALLBACK (nautilus_canvas_container_accessible_icon_removed_cb), 
8296 				  accessible);
8297 		g_signal_connect (container, "cleared",
8298 				  G_CALLBACK (nautilus_canvas_container_accessible_cleared_cb), 
8299 				  accessible);
8300 	}
8301 }
8302 
8303 static void
8304 nautilus_canvas_container_accessible_finalize (GObject *object)
8305 {
8306 	NautilusCanvasContainerAccessiblePrivate *priv;
8307 	int i;
8308 
8309 	priv = GET_ACCESSIBLE_PRIV (object);
8310 
8311 	if (priv->selection) {
8312 		g_list_free (priv->selection);
8313 	}
8314 
8315 	for (i = 0; i < LAST_ACTION; i++) {
8316 		if (priv->action_descriptions[i]) {
8317 			g_free (priv->action_descriptions[i]);
8318 		}
8319 	}
8320 
8321 	G_OBJECT_CLASS (nautilus_canvas_container_accessible_parent_class)->finalize (object);
8322 }
8323 
8324 static void
8325 nautilus_canvas_container_accessible_init (NautilusCanvasContainerAccessible *self)
8326 {
8327 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nautilus_canvas_container_accessible_get_type (),
8328 						  NautilusCanvasContainerAccessiblePrivate);
8329 }
8330 
8331 static void
8332 nautilus_canvas_container_accessible_class_init (NautilusCanvasContainerAccessibleClass *klass)
8333 {
8334 	AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
8335 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
8336 
8337 	gobject_class->finalize = nautilus_canvas_container_accessible_finalize;
8338 
8339 	atk_class->get_n_children = nautilus_canvas_container_accessible_get_n_children;
8340 	atk_class->ref_child = nautilus_canvas_container_accessible_ref_child;
8341 	atk_class->initialize = nautilus_canvas_container_accessible_initialize;
8342 
8343 	g_type_class_add_private (klass, sizeof (NautilusCanvasContainerAccessiblePrivate));
8344 }
8345 
8346 static AtkObject *
8347 get_accessible (GtkWidget *widget)
8348 {
8349 	AtkObject *accessible;
8350 	
8351 	if ((accessible = eel_accessibility_get_atk_object (widget))) {
8352 		return accessible;
8353 	}
8354 
8355 	accessible = g_object_new (nautilus_canvas_container_accessible_get_type (), "widget", widget, NULL);
8356 
8357 	return eel_accessibility_set_atk_object_return (widget, accessible);
8358 }
8359 
8360 gboolean
8361 nautilus_canvas_container_is_layout_rtl (NautilusCanvasContainer *container)
8362 {
8363 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), 0);
8364 
8365 	return container->details->layout_mode == NAUTILUS_CANVAS_LAYOUT_T_B_R_L ||
8366 		container->details->layout_mode == NAUTILUS_CANVAS_LAYOUT_R_L_T_B;
8367 }
8368 
8369 gboolean
8370 nautilus_canvas_container_is_layout_vertical (NautilusCanvasContainer *container)
8371 {
8372 	g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), FALSE);
8373 
8374 	return (container->details->layout_mode == NAUTILUS_CANVAS_LAYOUT_T_B_L_R ||
8375 		container->details->layout_mode == NAUTILUS_CANVAS_LAYOUT_T_B_R_L);
8376 }
8377 
8378 int
8379 nautilus_canvas_container_get_max_layout_lines_for_pango (NautilusCanvasContainer  *container)
8380 {
8381 	int limit;
8382 
8383 	if (nautilus_canvas_container_get_is_desktop (container)) {
8384 		limit = desktop_text_ellipsis_limit;
8385 	} else {
8386 		limit = text_ellipsis_limits[container->details->zoom_level];
8387 	}
8388 
8389 	if (limit <= 0) {
8390 		return G_MININT;
8391 	}
8392 
8393 	return -limit;
8394 }
8395 
8396 int
8397 nautilus_canvas_container_get_max_layout_lines (NautilusCanvasContainer  *container)
8398 {
8399 	int limit;
8400 
8401 	if (nautilus_canvas_container_get_is_desktop (container)) {
8402 		limit = desktop_text_ellipsis_limit;
8403 	} else {
8404 		limit = text_ellipsis_limits[container->details->zoom_level];
8405 	}
8406 
8407 	if (limit <= 0) {
8408 		return G_MAXINT;
8409 	}
8410 
8411 	return limit;
8412 }
8413 
8414 void
8415 nautilus_canvas_container_begin_loading (NautilusCanvasContainer *container)
8416 {
8417 	gboolean dummy;
8418 
8419 	if (nautilus_canvas_container_get_store_layout_timestamps (container)) {
8420 		container->details->layout_timestamp = UNDEFINED_TIME;
8421 		g_signal_emit (container,
8422 			       signals[GET_STORED_LAYOUT_TIMESTAMP], 0,
8423 			       NULL, &container->details->layout_timestamp, &dummy);
8424 	}
8425 }
8426 
8427 static void
8428 store_layout_timestamps_now (NautilusCanvasContainer *container)
8429 {
8430 	NautilusCanvasIcon *icon;
8431 	GList *p;
8432 	gboolean dummy;
8433 
8434 	container->details->layout_timestamp = time (NULL);
8435 	g_signal_emit (container,
8436 		       signals[STORE_LAYOUT_TIMESTAMP], 0,
8437 		       NULL, &container->details->layout_timestamp, &dummy);
8438 
8439 	for (p = container->details->icons; p != NULL; p = p->next) {
8440 		icon = p->data;
8441 
8442 		g_signal_emit (container,
8443 			       signals[STORE_LAYOUT_TIMESTAMP], 0,
8444 			       icon->data, &container->details->layout_timestamp, &dummy);
8445 	}
8446 }
8447 
8448 
8449 void
8450 nautilus_canvas_container_end_loading (NautilusCanvasContainer *container,
8451 				       gboolean               all_icons_added)
8452 {
8453 	if (all_icons_added &&
8454 	    nautilus_canvas_container_get_store_layout_timestamps (container)) {
8455 		if (container->details->new_icons == NULL) {
8456 			store_layout_timestamps_now (container);
8457 		} else {
8458 			container->details->store_layout_timestamps_when_finishing_new_icons = TRUE;
8459 		}
8460 	}
8461 }
8462 
8463 gboolean
8464 nautilus_canvas_container_get_store_layout_timestamps (NautilusCanvasContainer *container)
8465 {
8466 	return container->details->store_layout_timestamps;
8467 }
8468 
8469 
8470 void
8471 nautilus_canvas_container_set_store_layout_timestamps (NautilusCanvasContainer *container,
8472 						       gboolean               store_layout_timestamps)
8473 {
8474 	container->details->store_layout_timestamps = store_layout_timestamps;
8475 }
8476 
8477 
8478 #if ! defined (NAUTILUS_OMIT_SELF_CHECK)
8479 
8480 static char *
8481 check_compute_stretch (int icon_x, int icon_y, int icon_size,
8482 		       int start_pointer_x, int start_pointer_y,
8483 		       int end_pointer_x, int end_pointer_y)
8484 {
8485 	StretchState start, current;
8486 
8487 	start.icon_x = icon_x;
8488 	start.icon_y = icon_y;
8489 	start.icon_size = icon_size;
8490 	start.pointer_x = start_pointer_x;
8491 	start.pointer_y = start_pointer_y;
8492 	current.pointer_x = end_pointer_x;
8493 	current.pointer_y = end_pointer_y;
8494 
8495 	compute_stretch (&start, &current);
8496 
8497 	return g_strdup_printf ("%d,%d:%d",
8498 				current.icon_x,
8499 				current.icon_y,
8500 				current.icon_size);
8501 }
8502 
8503 void
8504 nautilus_self_check_canvas_container (void)
8505 {
8506 	EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 0, 0, 0, 0), "0,0:16");
8507 	EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 16, 16, 17, 17), "0,0:17");
8508 	EEL_CHECK_STRING_RESULT (check_compute_stretch (0, 0, 16, 16, 16, 17, 16), "0,0:16");
8509 	EEL_CHECK_STRING_RESULT (check_compute_stretch (100, 100, 64, 105, 105, 40, 40), "35,35:129");
8510 }
8511 
8512 #endif /* ! NAUTILUS_OMIT_SELF_CHECK */