summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarinus Schraal <foser@gentoo.org>2003-05-08 14:27:43 +0000
committerMarinus Schraal <foser@gentoo.org>2003-05-08 14:27:43 +0000
commit20cb3393e1197c7ff71f461938feaf5e4f49b356 (patch)
treebc556ea9febdd69791ec0d1c8f65336bcaf0b412 /gnome-base/nautilus/files
parentNew version 'n cleanup (diff)
downloadgentoo-2-20cb3393e1197c7ff71f461938feaf5e4f49b356.tar.gz
gentoo-2-20cb3393e1197c7ff71f461938feaf5e4f49b356.tar.bz2
gentoo-2-20cb3393e1197c7ff71f461938feaf5e4f49b356.zip
new version 'n cleanup
Diffstat (limited to 'gnome-base/nautilus/files')
-rw-r--r--gnome-base/nautilus/files/digest-nautilus-2.0.81
-rw-r--r--gnome-base/nautilus/files/digest-nautilus-2.2.0.21
-rw-r--r--gnome-base/nautilus/files/digest-nautilus-2.2.21
-rw-r--r--gnome-base/nautilus/files/digest-nautilus-2.2.41
-rw-r--r--gnome-base/nautilus/files/nautilus-2-snap_to_grid-r1.patch1188
5 files changed, 1189 insertions, 3 deletions
diff --git a/gnome-base/nautilus/files/digest-nautilus-2.0.8 b/gnome-base/nautilus/files/digest-nautilus-2.0.8
deleted file mode 100644
index 9bf044294aa8..000000000000
--- a/gnome-base/nautilus/files/digest-nautilus-2.0.8
+++ /dev/null
@@ -1 +0,0 @@
-MD5 761bed97624070aa29cca64fd56842b1 nautilus-2.0.8.tar.bz2 5126102
diff --git a/gnome-base/nautilus/files/digest-nautilus-2.2.0.2 b/gnome-base/nautilus/files/digest-nautilus-2.2.0.2
deleted file mode 100644
index 8feecf2947b5..000000000000
--- a/gnome-base/nautilus/files/digest-nautilus-2.2.0.2
+++ /dev/null
@@ -1 +0,0 @@
-MD5 27538efc26c651edf21d71ae0c81f9cf nautilus-2.2.0.2.tar.bz2 4414561
diff --git a/gnome-base/nautilus/files/digest-nautilus-2.2.2 b/gnome-base/nautilus/files/digest-nautilus-2.2.2
deleted file mode 100644
index 617bfea5a0f3..000000000000
--- a/gnome-base/nautilus/files/digest-nautilus-2.2.2
+++ /dev/null
@@ -1 +0,0 @@
-MD5 43e374e6b6579db98beca843520c9cd1 nautilus-2.2.2.tar.bz2 4454567
diff --git a/gnome-base/nautilus/files/digest-nautilus-2.2.4 b/gnome-base/nautilus/files/digest-nautilus-2.2.4
new file mode 100644
index 000000000000..5e24233fdbc4
--- /dev/null
+++ b/gnome-base/nautilus/files/digest-nautilus-2.2.4
@@ -0,0 +1 @@
+MD5 cb189d8a53dca17e5345261bd819c421 nautilus-2.2.4.tar.bz2 4657953
diff --git a/gnome-base/nautilus/files/nautilus-2-snap_to_grid-r1.patch b/gnome-base/nautilus/files/nautilus-2-snap_to_grid-r1.patch
new file mode 100644
index 000000000000..345eded02340
--- /dev/null
+++ b/gnome-base/nautilus/files/nautilus-2-snap_to_grid-r1.patch
@@ -0,0 +1,1188 @@
+Index: libnautilus-private/nautilus-icon-container.c
+===================================================================
+RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
+retrieving revision 1.339
+diff -u -r1.339 nautilus-icon-container.c
+--- libnautilus-private/nautilus-icon-container.c 23 Apr 2003 14:31:21 -0000 1.339
++++ libnautilus-private/nautilus-icon-container.c 3 May 2003 23:21:42 -0000
+@@ -101,9 +101,9 @@
+ #define STANDARD_ICON_GRID_WIDTH 155
+
+ /* Desktop layout mode defines */
+-#define DESKTOP_PAD_HORIZONTAL 30
++#define DESKTOP_PAD_HORIZONTAL 10
+ #define DESKTOP_PAD_VERTICAL 10
+-#define CELL_SIZE 20
++#define SNAP_SIZE 78
+
+ /* Value used to protect against icons being dragged outside of the desktop bounds */
+ #define DESKTOP_ICON_SAFETY_PAD 10
+@@ -116,6 +116,14 @@
+ #define MINIMUM_EMBEDDED_TEXT_RECT_WIDTH 20
+ #define MINIMUM_EMBEDDED_TEXT_RECT_HEIGHT 20
+
++#define SNAP_HORIZONTAL(func,x) ((func ((double)((x) - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE) * SNAP_SIZE) + DESKTOP_PAD_HORIZONTAL)
++#define SNAP_VERTICAL(func, y) ((func ((double)((y) - DESKTOP_PAD_VERTICAL) / SNAP_SIZE) * SNAP_SIZE) + DESKTOP_PAD_VERTICAL)
++
++#define SNAP_NEAREST_HORIZONTAL(x) SNAP_HORIZONTAL (eel_round, x)
++#define SNAP_NEAREST_VERTICAL(y) SNAP_VERTICAL (eel_round, y)
++
++#define SNAP_CEIL_HORIZONTAL(x) SNAP_HORIZONTAL (ceil, x)
++#define SNAP_CEIL_VERTICAL(y) SNAP_VERTICAL (ceil, y)
+
+ enum {
+ NAUTILUS_TYPESELECT_FLUSH_DELAY = 1000000
+@@ -220,6 +228,15 @@
+ CLEARED,
+ LAST_SIGNAL
+ };
++
++typedef struct {
++ int **icon_grid;
++ int *grid_memory;
++ int num_rows;
++ int num_columns;
++ gboolean tight;
++} PlacementGrid;
++
+ static guint signals[LAST_SIGNAL];
+
+ /* Functions dealing with NautilusIcons. */
+@@ -335,6 +352,7 @@
+ icon_set_size (NautilusIconContainer *container,
+ NautilusIcon *icon,
+ guint icon_size,
++ gboolean snap,
+ gboolean update_position)
+ {
+ guint old_size;
+@@ -350,8 +368,8 @@
+ (container->details->zoom_level);
+ nautilus_icon_container_move_icon (container, icon,
+ icon->x, icon->y,
+- scale, scale,
+- FALSE, update_position);
++ scale, scale, FALSE,
++ snap, update_position);
+ }
+
+ static void
+@@ -398,6 +416,15 @@
+ if (icon == container->details->stretch_icon) {
+ container->details->stretch_icon = NULL;
+ nautilus_icon_canvas_item_set_show_stretch_handles (icon->item, FALSE);
++ /* snap the icon if necessary */
++ if (container->details->keep_aligned) {
++ nautilus_icon_container_move_icon (container,
++ icon,
++ icon->x, icon->y,
++ icon->scale_x, icon->scale_y,
++ FALSE, TRUE, TRUE);
++ }
++
+ emit_stretch_ended (container, icon);
+ }
+
+@@ -1004,150 +1031,313 @@
+ g_array_free (positions, TRUE);
+ }
+
+-/* Search for available space at location */
+-static gboolean
+-find_open_grid_space (NautilusIcon *icon, int **icon_grid, int num_rows,
+- int num_columns, int row, int column)
+-{
+- int row_index, column_index;
+- int x1, x2, y1, y2;
+- double width, height;
+- int qwidth, qheight;
+-
+- /* Get icon dimensions */
+- icon_get_bounding_box (icon, &x1, &y1, &x2, &y2);
+-
+- width = (x2 - x1) + DESKTOP_PAD_HORIZONTAL;
+- height = (y2 - y1) + DESKTOP_PAD_VERTICAL;
+-
+- /* Convert to grid coordinates */
+- qwidth = ceil (width / CELL_SIZE);
+- qheight = ceil (height / CELL_SIZE);
++static void
++snap_position (NautilusIconContainer *container,
++ NautilusIcon *icon,
++ int *x, int *y)
++{
++ int center_x;
++ int baseline_y;
++ int icon_width;
++ int icon_height;
++ ArtDRect icon_position;
++
++ if (*x < DESKTOP_PAD_HORIZONTAL) {
++ *x = DESKTOP_PAD_HORIZONTAL;
++ }
+
+- if ((row + qwidth > num_rows) || (column + qheight > num_columns)) {
+- return FALSE;
++ if (*y < DESKTOP_PAD_VERTICAL) {
++ *y = DESKTOP_PAD_VERTICAL;
+ }
+
+- qwidth += row;
+- qheight += column;
++ icon_position = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
++ icon_width = icon_position.x1 - icon_position.x0;
++ icon_height = icon_position.y1 - icon_position.y0;
+
+- for (row_index = row; row_index < qwidth; row_index++) {
+- for (column_index = column; column_index < qheight; column_index++) {
+- if (icon_grid [row_index] [column_index] == 1) {
+- return FALSE;
+- }
+- }
+- }
+- return TRUE;
++ center_x = *x + icon_width / 2;
++ *x = SNAP_NEAREST_HORIZONTAL (center_x) - (icon_width / 2);
++
++ /* Find the grid position vertically and place on the proper baseline */
++ baseline_y = *y + icon_height;
++ baseline_y = SNAP_NEAREST_VERTICAL (baseline_y);
++ *y = baseline_y - (icon_position.y1 - icon_position.y0);
++}
++
++static int
++compare_icons_by_position (gconstpointer a, gconstpointer b)
++{
++ NautilusIcon *icon_a, *icon_b;
++ int x1, y1, x2, y2;
++ int center_a;
++ int center_b;
++
++ icon_a = (NautilusIcon*)a;
++ icon_b = (NautilusIcon*)b;
++
++ icon_get_bounding_box (icon_a, &x1, &y1, &x2, &y2);
++ center_a = x1 + (x2 - x1) / 2;
++ icon_get_bounding_box (icon_b, &x1, &y1, &x2, &y2);
++ center_b = x1 + (x2 - x1) / 2;
++
++ return center_a == center_b ?
++ icon_a->y - icon_b->y :
++ center_a - center_b;
+ }
+
++static PlacementGrid *
++placement_grid_new (NautilusIconContainer *container, gboolean tight)
++{
++ PlacementGrid *grid;
++ int width, height;
++ int num_columns;
++ int num_rows;
++ int i;
++
++ /* Get container dimensions */
++ width = GTK_WIDGET (container)->allocation.width /
++ EEL_CANVAS (container)->pixels_per_unit
++ - container->details->left_margin
++ - container->details->right_margin;
++ height = GTK_WIDGET (container)->allocation.height /
++ EEL_CANVAS (container)->pixels_per_unit
++ - container->details->top_margin
++ - container->details->bottom_margin;
++
++ num_columns = width / SNAP_SIZE;
++ num_rows = height / SNAP_SIZE;
++
++ if (num_columns == 0 || num_rows == 0) {
++ return NULL;
++ }
++
++ grid = g_new0 (PlacementGrid, 1);
++ grid->tight = tight;
++ grid->num_columns = num_columns;
++ grid->num_rows = num_rows;
++
++ grid->grid_memory = g_new0 (int, (num_rows * num_columns));
++ grid->icon_grid = g_new0 (int *, num_columns);
++
++ for (i = 0; i < num_columns; i++) {
++ grid->icon_grid[i] = grid->grid_memory + (i * num_rows);
++ }
++
++ return grid;
++}
+
+ static void
+-get_best_empty_grid_location (NautilusIcon *icon, int **icon_grid, int num_rows,
+- int num_columns, int *x, int *y)
++placement_grid_free (PlacementGrid *grid)
+ {
+- gboolean found_space;
+- int row, column;
++ g_free (grid->icon_grid);
++ g_free (grid->grid_memory);
++ g_free (grid);
++}
++
++static gboolean
++placement_grid_position_is_free (PlacementGrid *grid, ArtIRect pos)
++{
++ int x, y;
+
+- g_assert (icon_grid != NULL);
+- g_assert (x != NULL);
+- g_assert (y != NULL);
+-
+- found_space = FALSE;
+-
+- /* Set up default fallback position */
+- *x = num_columns * CELL_SIZE;
+- *y = num_rows * CELL_SIZE;
+-
+- /* Find best empty location */
+- for (row = 0; row < num_rows; row++) {
+- for (column = 0; column < num_columns; column++) {
+- found_space = find_open_grid_space (icon, icon_grid, num_rows,
+- num_columns, row, column);
+- if (found_space) {
+- *x = row * CELL_SIZE;
+- *y = column * CELL_SIZE;
+-
+- /* Correct for padding */
+- if (*x < DESKTOP_PAD_HORIZONTAL) {
+- *x = DESKTOP_PAD_HORIZONTAL;
+- }
+- if (*y < DESKTOP_PAD_VERTICAL) {
+- *y = DESKTOP_PAD_VERTICAL;
+- }
+- return;
++ g_return_val_if_fail (pos.x0 >= 0 && pos.x0 < grid->num_columns, TRUE);
++ g_return_val_if_fail (pos.y0 >= 0 && pos.y0 < grid->num_rows, TRUE);
++ g_return_val_if_fail (pos.x1 >= 0 && pos.x1 < grid->num_columns, TRUE);
++ g_return_val_if_fail (pos.y1 >= 0 && pos.y1 < grid->num_rows, TRUE);
++
++ for (x = pos.x0; x <= pos.x1; x++) {
++ for (y = pos.y0; y <= pos.y1; y++) {
++ if (grid->icon_grid[x][y] != 0) {
++ return FALSE;
+ }
+- }
++ }
+ }
++
++ return TRUE;
+ }
+
+ static void
+-mark_icon_location_in_grid (NautilusIcon *icon, int **icon_grid, int num_rows, int num_columns)
++placement_grid_mark (PlacementGrid *grid, ArtIRect pos)
+ {
+- int x1, x2, y1, y2;
+- double width, height;
+- int qx, qy, qwidth, qheight, qy_index;
+- int grid_width, grid_height;
+-
+- icon_get_bounding_box (icon, &x1, &y1, &x2, &y2);
+-
+- width = (x2 - x1) + DESKTOP_PAD_HORIZONTAL;
+- height = (y2 - y1) + DESKTOP_PAD_VERTICAL;
+-
+- /* Convert x and y to our quantized grid value */
+- qx = icon->x / CELL_SIZE;
+- qy = icon->y / CELL_SIZE;
+- qwidth = ceil (width / CELL_SIZE);
+- qheight = ceil (height / CELL_SIZE);
+-
+- /* Check and correct for edge conditions */
+- grid_width = num_rows;
+- grid_height = num_columns;
++ int x, y;
+
+- if ((qx + qwidth) > grid_width) {
+- qwidth = grid_width;
+- } else {
+- qwidth = qx + qwidth;
++ g_return_if_fail (pos.x0 >= 0 && pos.x0 < grid->num_columns);
++ g_return_if_fail (pos.y0 >= 0 && pos.y0 < grid->num_rows);
++ g_return_if_fail (pos.x1 >= 0 && pos.x1 < grid->num_columns);
++ g_return_if_fail (pos.y1 >= 0 && pos.y1 < grid->num_rows);
++
++ for (x = pos.x0; x <= pos.x1; x++) {
++ for (y = pos.y0; y <= pos.y1; y++) {
++ grid->icon_grid[x][y] = 1;
++ }
+ }
+- if ((qy + qheight) > grid_height) {
+- qheight = grid_height;
++}
++
++static void
++canvas_position_to_grid_position (PlacementGrid *grid,
++ ArtIRect canvas_position,
++ ArtIRect *grid_position)
++{
++ /* The first bit of this block will identify all intersections
++ * that the icon actually crosses. The second bit will mark
++ * any intersections that the icon is adjacent to.
++ * The first causes minimal moving around during a snap, but
++ * can end up with partially overlapping icons. The second one won't
++ * allow any overlapping, but can cause more movement to happen
++ * during a snap. */
++ if (grid->tight) {
++ grid_position->x0 = ceil ((double)(canvas_position.x0 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE);
++ grid_position->y0 = ceil ((double)(canvas_position.y0 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE);
++ grid_position->x1 = floor ((double)(canvas_position.x1 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE);
++ grid_position->y1 = floor ((double)(canvas_position.y1 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE);
+ } else {
+- qheight = qy + qheight;
++ grid_position->x0 = floor ((double)(canvas_position.x0 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE);
++ grid_position->y0 = floor ((double)(canvas_position.y0 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE);
++ grid_position->x1 = ceil ((double)(canvas_position.x1 - DESKTOP_PAD_HORIZONTAL) / SNAP_SIZE);
++ grid_position->y1 = ceil ((double)(canvas_position.y1 - DESKTOP_PAD_VERTICAL) / SNAP_SIZE);
+ }
++
++ grid_position->x0 = CLAMP (grid_position->x0, 0, grid->num_columns - 1);
++ grid_position->y0 = CLAMP (grid_position->y0, 0, grid->num_rows - 1);
++ grid_position->x1 = CLAMP (grid_position->x1, grid_position->x0, grid->num_columns - 1);
++ grid_position->y1 = CLAMP (grid_position->y1, grid_position->y0, grid->num_rows - 1);
++}
++
++static void
++placement_grid_mark_icon (PlacementGrid *grid, NautilusIcon *icon)
++{
++ ArtIRect icon_pos;
++ ArtIRect grid_pos;
+
+- /* Mark location */
+- for (; qx < qwidth; qx++) {
+- for (qy_index = qy; qy_index < qheight; qy_index++) {
+- icon_grid [qx] [qy_index] = 1;
++ icon_get_bounding_box (icon,
++ &icon_pos.x0, &icon_pos.y0,
++ &icon_pos.x1, &icon_pos.y1);
++ canvas_position_to_grid_position (grid,
++ icon_pos,
++ &grid_pos);
++ placement_grid_mark (grid, grid_pos);
++}
++
++static void
++find_empty_location (NautilusIconContainer *container,
++ PlacementGrid *grid,
++ NautilusIcon *icon,
++ int start_x,
++ int start_y,
++ int *x,
++ int *y)
++{
++ double icon_width, icon_height;
++ int canvas_width;
++ int canvas_height;
++ ArtIRect icon_position;
++ ArtDRect pixbuf_rect;
++ gboolean collision;
++
++ /* Get container dimensions */
++ canvas_width = GTK_WIDGET (container)->allocation.width /
++ EEL_CANVAS (container)->pixels_per_unit
++ - container->details->left_margin
++ - container->details->right_margin;
++ canvas_height = GTK_WIDGET (container)->allocation.height /
++ EEL_CANVAS (container)->pixels_per_unit
++ - container->details->top_margin
++ - container->details->bottom_margin;
++
++ icon_get_bounding_box (icon,
++ &icon_position.x0, &icon_position.y0,
++ &icon_position.x1, &icon_position.y1);
++ icon_width = icon_position.x1 - icon_position.x0;
++ icon_height = icon_position.y1 - icon_position.y0;
++
++ pixbuf_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
++
++ /* Start the icon on a grid location */
++ snap_position (container, icon, &start_x, &start_y);
++
++ icon_position.x0 = start_x;
++ icon_position.y0 = start_y;
++ icon_position.x1 = icon_position.x0 + icon_width;
++ icon_position.y1 = icon_position.y0 + icon_height;
++
++ do {
++ ArtIRect grid_position;
++
++ collision = FALSE;
++
++ canvas_position_to_grid_position (grid,
++ icon_position,
++ &grid_position);
++
++ if (!placement_grid_position_is_free (grid, grid_position)) {
++ icon_position.y0 += SNAP_SIZE;
++ icon_position.y1 = icon_position.y0 + icon_width;
++
++ if (icon_position.y1 + DESKTOP_PAD_VERTICAL > canvas_height) {
++ /* Move to the next column */
++ icon_position.y0 = DESKTOP_PAD_VERTICAL + SNAP_SIZE - (pixbuf_rect.y1 - pixbuf_rect.y0);
++ while (icon_position.y0 < DESKTOP_PAD_VERTICAL) {
++ icon_position.y0 += SNAP_SIZE;
++ }
++ icon_position.y1 = icon_position.y0 + icon_width;
++
++ icon_position.x0 += SNAP_SIZE;
++ icon_position.x1 = icon_position.x0 + icon_height;
++ }
++
++ collision = TRUE;
+ }
+- }
++ } while (collision && (icon_position.x1 < canvas_width));
++
++ *x = icon_position.x0;
++ *y = icon_position.y0;
+ }
+
+-static void
+-mark_icon_locations_in_grid (GList *icon_list, int **icon_grid, int num_rows, int num_columns)
++static void
++align_icons (NautilusIconContainer *container)
+ {
+- GList *p;
+- NautilusIcon *icon;
++ GList *unplaced_icons;
++ GList *l;
++ PlacementGrid *grid;
++
++ unplaced_icons = g_list_copy (container->details->icons);
+
+- /* Mark filled grid locations */
+- for (p = icon_list; p != NULL; p = p->next) {
+- icon = p->data;
+- mark_icon_location_in_grid (icon, icon_grid, num_rows, num_columns);
++ unplaced_icons = g_list_sort (unplaced_icons,
++ compare_icons_by_position);
++
++ grid = placement_grid_new (container, TRUE);
++
++ if (!grid) {
++ return;
+ }
++
++ for (l = unplaced_icons; l != NULL; l = l->next) {
++ NautilusIcon *icon;
++ int x, y;
++
++ icon = l->data;
++ x = icon->x;
++ y = icon->y;
++
++ find_empty_location (container, grid,
++ icon, x, y, &x, &y);
++
++ icon_set_position (icon, x, y);
++
++ placement_grid_mark_icon (grid, icon);
++ }
++
++ g_list_free (unplaced_icons);
++
++ placement_grid_free (grid);
+ }
+
+ static void
+ lay_down_icons_tblr (NautilusIconContainer *container, GList *icons)
+ {
+ GList *p, *placed_icons, *unplaced_icons;
+- int index, total, new_length, placed;
++ int total, new_length, placed;
+ NautilusIcon *icon;
+- int width, height, max_width, icon_width, icon_height;
++ int width, height, max_width, column_width, icon_width, icon_height;
+ int x, y, x1, x2, y1, y2;
+- int *grid_memory;
+- int **icon_grid;
+- int num_rows, num_columns;
+- int row, column;
+ ArtDRect icon_rect;
+
+ /* Get container dimensions */
+@@ -1168,6 +1358,7 @@
+ new_length = g_list_length (icons);
+ placed = total - new_length;
+ if (placed > 0) {
++ PlacementGrid *grid;
+ /* Add only placed icons in list */
+ for (p = container->details->icons; p != NULL; p = p->next) {
+ icon = p->data;
+@@ -1181,54 +1372,40 @@
+ }
+ placed_icons = g_list_reverse (placed_icons);
+ unplaced_icons = g_list_reverse (unplaced_icons);
+-
+- /* Allocate grid array */
+- num_rows = width / CELL_SIZE;
+- num_columns = height / CELL_SIZE;
+-
+- /* Allocate array memory */
+- grid_memory = malloc (num_rows * num_columns * sizeof (int *));
+- g_assert (grid_memory);
+-
+- /* Allocate room for the pointers to the rows */
+- icon_grid = malloc (num_rows * sizeof (int *));
+- g_assert (icon_grid);
+-
+- /* Point to array pointers */
+- for (index = 0; index < num_rows; index++) {
+- icon_grid[index] = grid_memory + (index * num_columns);
+- }
+-
+- /* Set all grid values to unfilled */
+- for (row = 0; row < num_rows; row++) {
+- for (column = 0; column < num_columns; column++) {
+- icon_grid [row] [column] = 0;
+- }
+- }
+-
+- /* Mark filled grid locations */
+- mark_icon_locations_in_grid (placed_icons, icon_grid, num_rows, num_columns);
+
+- /* Place unplaced icons in the best locations */
+- for (p = unplaced_icons; p != NULL; p = p->next) {
+- icon = p->data;
+- get_best_empty_grid_location (icon, icon_grid, num_rows, num_columns,
+- &x, &y);
++ grid = placement_grid_new (container, FALSE);
+
+- icon_get_bounding_box (icon, &x1, &y1, &x2, &y2);
+- icon_width = x2 - x1;
++ if (grid) {
++ for (p = placed_icons; p != NULL; p = p->next) {
++ placement_grid_mark_icon
++ (grid, (NautilusIcon*)p->data);
++ }
+
+- icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
++ /* Place unplaced icons in the best locations */
++ for (p = unplaced_icons; p != NULL; p = p->next) {
++ icon = p->data;
++
++ icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
++ icon_get_bounding_box (icon,
++ &x1, &y1, &x2, &y2);
++
++ /* Start the icon in the first column */
++ x = DESKTOP_PAD_HORIZONTAL + SNAP_SIZE - ((x2 - x1) / 2);
++ y = DESKTOP_PAD_VERTICAL + SNAP_SIZE - (icon_rect.y1 - icon_rect.y0);
++
++ find_empty_location (container,
++ grid,
++ icon,
++ x, y,
++ &x, &y);
++
++ icon_set_position (icon, x, y);
++ placement_grid_mark_icon (grid, icon);
++ }
+
+- icon_set_position (icon,
+- x + (icon_width - (icon_rect.x1 - icon_rect.x0)) / 2, y);
+- /* Add newly placed icon to grid */
+- mark_icon_location_in_grid (icon, icon_grid, num_rows, num_columns);
++ placement_grid_free (grid);
+ }
+-
+- /* Clean up */
+- free (icon_grid);
+- free (grid_memory);
++
+ g_list_free (placed_icons);
+ g_list_free (unplaced_icons);
+ } else {
+@@ -1236,18 +1413,32 @@
+ x = DESKTOP_PAD_HORIZONTAL;
+
+ while (icons != NULL) {
++ int center_x;
++ int baseline;
++ gboolean should_snap;
++
++ should_snap = !(container->details->tighter_layout && !container->details->keep_aligned);
++
+ y = DESKTOP_PAD_VERTICAL;
+- max_width = 0;
+
++ max_width = 0;
++
+ /* Calculate max width for column */
+ for (p = icons; p != NULL; p = p->next) {
+ icon = p->data;
+-
+ icon_get_bounding_box (icon, &x1, &y1, &x2, &y2);
+
+ icon_width = x2 - x1;
+ icon_height = y2 - y1;
+-
++
++ if (should_snap) {
++ /* Snap the baseline to a grid position */
++ icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
++ baseline = y + (icon_rect.y1 - icon_rect.y0);
++ baseline = SNAP_CEIL_VERTICAL (baseline);
++ y = baseline - (icon_rect.y1 - icon_rect.y0);
++ }
++
+ /* Check and see if we need to move to a new column */
+ if (y != DESKTOP_PAD_VERTICAL && y > height - icon_height) {
+ break;
+@@ -1261,6 +1452,15 @@
+ }
+
+ y = DESKTOP_PAD_VERTICAL;
++
++ center_x = x + max_width / 2;
++ column_width = max_width;
++ if (should_snap) {
++ /* Find the grid column to center on */
++ center_x = SNAP_CEIL_HORIZONTAL (center_x);
++ column_width = (center_x - x) + (max_width / 2);
++ }
++
+ /* Lay out column */
+ for (p = icons; p != NULL; p = p->next) {
+ icon = p->data;
+@@ -1269,15 +1469,21 @@
+ icon_height = y2 - y1;
+
+ icon_rect = nautilus_icon_canvas_item_get_icon_rectangle (icon->item);
++
++ if (should_snap) {
++ baseline = y + (icon_rect.y1 - icon_rect.y0);
++ baseline = SNAP_CEIL_VERTICAL (baseline);
++ y = baseline - (icon_rect.y1 - icon_rect.y0);
++ }
+
+ /* Check and see if we need to move to a new column */
+ if (y != DESKTOP_PAD_VERTICAL && y > height - icon_height) {
+- x += max_width + DESKTOP_PAD_HORIZONTAL;
++ x += column_width + DESKTOP_PAD_HORIZONTAL;
+ break;
+ }
+
+ icon_set_position (icon,
+- x + max_width / 2 - (icon_rect.x1 - icon_rect.x0) / 2,
++ center_x - (icon_rect.x1 - icon_rect.x0) / 2,
+ y);
+
+ y += icon_height + DESKTOP_PAD_VERTICAL;
+@@ -1493,6 +1699,7 @@
+ int x, int y,
+ double scale_x, double scale_y,
+ gboolean raise,
++ gboolean snap,
+ gboolean update_position)
+ {
+ NautilusIconContainerDetails *details;
+@@ -1507,13 +1714,6 @@
+ end_renaming_mode (container, TRUE);
+ }
+
+- if (!details->auto_layout) {
+- if (x != icon->x || y != icon->y) {
+- icon_set_position (icon, x, y);
+- emit_signal = update_position;
+- }
+- }
+-
+ if (scale_x != icon->scale_x || scale_y != icon->scale_y) {
+ icon->scale_x = scale_x;
+ icon->scale_y = scale_y;
+@@ -1522,7 +1722,17 @@
+ redo_layout (container);
+ emit_signal = TRUE;
+ }
++ }
++
++ if (!details->auto_layout) {
++ if (details->keep_aligned && snap) {
++ snap_position (container, icon, &x, &y);
++ }
+
++ if (x != icon->x || y != icon->y) {
++ icon_set_position (icon, x, y);
++ emit_signal = update_position;
++ }
+ }
+
+ if (emit_signal) {
+@@ -2598,6 +2808,12 @@
+ g_source_remove (container->details->stretch_idle_id);
+ container->details->stretch_idle_id = 0;
+ }
++
++ if (container->details->align_idle_id != 0) {
++ g_source_remove (container->details->align_idle_id);
++ container->details->align_idle_id = 0;
++ }
++
+
+ nautilus_icon_container_flush_typeselect_state (container);
+
+@@ -2985,7 +3201,7 @@
+ &world_x, &world_y);
+
+ icon_set_position (icon, world_x, world_y);
+- icon_set_size (container, icon, stretch_state.icon_size, FALSE);
++ icon_set_size (container, icon, stretch_state.icon_size, FALSE, FALSE);
+
+ container->details->stretch_idle_id = 0;
+
+@@ -3062,6 +3278,7 @@
+ icon_set_size (container,
+ stretched_icon,
+ container->details->stretch_initial_size,
++ TRUE,
+ TRUE);
+
+ container->details->stretch_icon = NULL;
+@@ -5113,7 +5330,7 @@
+ nautilus_icon_container_move_icon (container, icon,
+ icon->x, icon->y,
+ 1.0, 1.0,
+- FALSE, TRUE);
++ FALSE, TRUE, TRUE);
+ }
+ }
+ }
+@@ -5251,6 +5468,57 @@
+ }
+ }
+
++gboolean
++nautilus_icon_container_is_keep_aligned (NautilusIconContainer *container)
++{
++ return container->details->keep_aligned;
++}
++
++static gboolean
++align_icons_callback (gpointer callback_data)
++{
++ NautilusIconContainer *container;
++
++ container = NAUTILUS_ICON_CONTAINER (callback_data);
++ align_icons (container);
++ container->details->align_idle_id = 0;
++
++ return FALSE;
++}
++
++static void
++unschedule_align_icons (NautilusIconContainer *container)
++{
++ if (container->details->align_idle_id != 0) {
++ g_source_remove (container->details->align_idle_id);
++ container->details->align_idle_id = 0;
++ }
++}
++
++static void
++schedule_align_icons (NautilusIconContainer *container)
++{
++ if (container->details->align_idle_id == 0
++ && container->details->has_been_allocated) {
++ container->details->align_idle_id = g_idle_add
++ (align_icons_callback, container);
++ }
++}
++
++void
++nautilus_icon_container_set_keep_aligned (NautilusIconContainer *container,
++ gboolean keep_aligned)
++{
++ if (container->details->keep_aligned != keep_aligned) {
++ container->details->keep_aligned = keep_aligned;
++
++ if (keep_aligned && !container->details->auto_layout) {
++ schedule_align_icons (container);
++ } else {
++ unschedule_align_icons (container);
++ }
++ }
++}
+
+ void
+ nautilus_icon_container_set_layout_mode (NautilusIconContainer *container,
+Index: libnautilus-private/nautilus-icon-container.h
+===================================================================
+RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.h,v
+retrieving revision 1.78
+diff -u -r1.78 nautilus-icon-container.h
+--- libnautilus-private/nautilus-icon-container.h 7 Apr 2003 11:56:03 -0000 1.78
++++ libnautilus-private/nautilus-icon-container.h 3 May 2003 23:21:42 -0000
+@@ -205,6 +205,10 @@
+ gboolean nautilus_icon_container_is_tighter_layout (NautilusIconContainer *container);
+ void nautilus_icon_container_set_tighter_layout (NautilusIconContainer *container,
+ gboolean tighter_layout);
++
++gboolean nautilus_icon_container_is_keep_aligned (NautilusIconContainer *container);
++void nautilus_icon_container_set_keep_aligned (NautilusIconContainer *container,
++ gboolean keep_aligned);
+ void nautilus_icon_container_set_layout_mode (NautilusIconContainer *container,
+ NautilusIconLayoutMode mode);
+ void nautilus_icon_container_sort (NautilusIconContainer *container);
+Index: libnautilus-private/nautilus-icon-dnd.c
+===================================================================
+RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-dnd.c,v
+retrieving revision 1.130
+diff -u -r1.130 nautilus-icon-dnd.c
+--- libnautilus-private/nautilus-icon-dnd.c 23 Apr 2003 09:49:47 -0000 1.130
++++ libnautilus-private/nautilus-icon-dnd.c 3 May 2003 23:21:43 -0000
+@@ -811,7 +811,7 @@
+ (container, icon,
+ world_x + item->icon_x, world_y + item->icon_y,
+ icon->scale_x, icon->scale_y,
+- TRUE, TRUE);
++ TRUE, TRUE, TRUE);
+ }
+ moved_icons = g_list_prepend (moved_icons, icon);
+ }
+Index: libnautilus-private/nautilus-icon-private.h
+===================================================================
+RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-private.h,v
+retrieving revision 1.71
+diff -u -r1.71 nautilus-icon-private.h
+--- libnautilus-private/nautilus-icon-private.h 27 Mar 2003 12:53:07 -0000 1.71
++++ libnautilus-private/nautilus-icon-private.h 3 May 2003 23:21:43 -0000
+@@ -177,6 +177,9 @@
+ /* Idle handler for stretch code */
+ guint stretch_idle_id;
+
++ /* Align idle id */
++ guint align_idle_id;
++
+ /* DnD info. */
+ NautilusIconDndInfo *dnd_info;
+
+@@ -215,7 +218,10 @@
+ /* Layout mode */
+ NautilusIconLayoutMode layout_mode;
+
+- /* Set to TRUE after first allocation has been done */
++ /* Should the container keep icons aligned to a grid */
++ gboolean keep_aligned;
++
++ /* Set to TRUE after first allocation has been done */
+ gboolean has_been_allocated;
+
+ /* Is the container fixed or resizable */
+@@ -252,6 +258,7 @@
+ double scale_x,
+ double scale_y,
+ gboolean raise,
++ gboolean snap,
+ gboolean update_position);
+ void nautilus_icon_container_select_list_unselect_others (NautilusIconContainer *container,
+ GList *icons);
+Index: libnautilus-private/nautilus-metadata.h
+===================================================================
+RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-metadata.h,v
+retrieving revision 1.25
+diff -u -r1.25 nautilus-metadata.h
+--- libnautilus-private/nautilus-metadata.h 19 Dec 2002 19:56:36 -0000 1.25
++++ libnautilus-private/nautilus-metadata.h 3 May 2003 23:21:43 -0000
+@@ -53,6 +53,7 @@
+ #define NAUTILUS_METADATA_KEY_ICON_VIEW_TIGHTER_LAYOUT "icon_view_tighter_layout"
+ #define NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY "icon_view_sort_by"
+ #define NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED "icon_view_sort_reversed"
++#define NAUTILUS_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED "icon_view_keep_aligned"
+
+ #define NAUTILUS_METADATA_KEY_LIST_VIEW_ZOOM_LEVEL "list_view_zoom_level"
+ #define NAUTILUS_METADATA_KEY_LIST_VIEW_SORT_COLUMN "list_view_sort_column"
+Index: src/file-manager/fm-desktop-icon-view.c
+===================================================================
+RCS file: /cvs/gnome/nautilus/src/file-manager/fm-desktop-icon-view.c,v
+retrieving revision 1.202
+diff -u -r1.202 fm-desktop-icon-view.c
+--- src/file-manager/fm-desktop-icon-view.c 23 Apr 2003 10:49:38 -0000 1.202
++++ src/file-manager/fm-desktop-icon-view.c 3 May 2003 23:21:43 -0000
+@@ -121,6 +121,7 @@
+ FMDesktopIconView *icon_view);
+ static void update_desktop_directory (UpdateType type);
+ static gboolean real_supports_auto_layout (FMIconView *view);
++static gboolean real_supports_keep_aligned (FMIconView *view);
+ static void real_merge_menus (FMDirectoryView *view);
+ static void real_update_menus (FMDirectoryView *view);
+ static gboolean real_supports_zooming (FMDirectoryView *view);
+@@ -300,6 +301,7 @@
+ FM_DIRECTORY_VIEW_CLASS (class)->supports_zooming = real_supports_zooming;
+
+ FM_ICON_VIEW_CLASS (class)->supports_auto_layout = real_supports_auto_layout;
++ FM_ICON_VIEW_CLASS (class)->supports_keep_aligned = real_supports_keep_aligned;
+ }
+
+ static void
+@@ -1470,6 +1472,12 @@
+ * fixed-size window.
+ */
+ return FALSE;
++}
++
++static gboolean
++real_supports_keep_aligned (FMIconView *view)
++{
++ return TRUE;
+ }
+
+ static gboolean
+Index: src/file-manager/fm-icon-view.c
+===================================================================
+RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.c,v
+retrieving revision 1.278
+diff -u -r1.278 fm-icon-view.c
+--- src/file-manager/fm-icon-view.c 7 Apr 2003 11:56:04 -0000 1.278
++++ src/file-manager/fm-icon-view.c 3 May 2003 23:21:43 -0000
+@@ -98,10 +98,12 @@
+ #define COMMAND_TIGHTER_LAYOUT "/commands/Tighter Layout"
+ #define COMMAND_SORT_REVERSED "/commands/Reversed Order"
+ #define COMMAND_CLEAN_UP "/commands/Clean Up"
++#define COMMAND_KEEP_ALIGNED "/commands/Keep Aligned"
+
+ #define ID_MANUAL_LAYOUT "Manual Layout"
+ #define ID_TIGHTER_LAYOUT "Tighter Layout"
+ #define ID_SORT_REVERSED "Reversed Order"
++#define ID_KEEP_ALIGNED "Keep Aligned"
+
+ typedef struct {
+ NautilusFileSortType sort_type;
+@@ -578,6 +580,16 @@
+ supports_auto_layout, (view));
+ }
+
++static gboolean
++fm_icon_view_supports_keep_aligned (FMIconView *view)
++{
++ g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
++
++ return EEL_CALL_METHOD_WITH_RETURN_VALUE
++ (FM_ICON_VIEW_CLASS, view,
++ supports_keep_aligned, (view));
++}
++
+ static void
+ update_layout_menus (FMIconView *view)
+ {
+@@ -617,6 +629,18 @@
+ nautilus_bonobo_set_sensitive
+ (view->details->ui, COMMAND_CLEAN_UP, !is_auto_layout);
+
++
++ nautilus_bonobo_set_hidden (view->details->ui,
++ COMMAND_KEEP_ALIGNED,
++ !fm_icon_view_supports_keep_aligned (view));
++
++ nautilus_bonobo_set_toggle_state
++ (view->details->ui, COMMAND_KEEP_ALIGNED,
++ nautilus_icon_container_is_keep_aligned (get_icon_container (view)));
++
++ nautilus_bonobo_set_sensitive
++ (view->details->ui, COMMAND_KEEP_ALIGNED, !is_auto_layout);
++
+ bonobo_ui_component_thaw (view->details->ui, NULL);
+ }
+
+@@ -753,6 +777,41 @@
+ sort_reversed);
+ }
+
++static gboolean
++get_default_directory_keep_aligned (void)
++{
++ return TRUE;
++}
++
++static gboolean
++fm_icon_view_get_directory_keep_aligned (FMIconView *icon_view,
++ NautilusFile *file)
++{
++ if (!fm_icon_view_supports_keep_aligned (icon_view)) {
++ return FALSE;
++ }
++
++ return nautilus_file_get_boolean_metadata
++ (file,
++ NAUTILUS_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED,
++ get_default_directory_keep_aligned ());
++}
++
++static void
++fm_icon_view_set_directory_keep_aligned (FMIconView *icon_view,
++ NautilusFile *file,
++ gboolean keep_aligned)
++{
++ if (!fm_icon_view_supports_keep_aligned (icon_view)) {
++ return;
++ }
++
++ nautilus_file_set_boolean_metadata
++ (file, NAUTILUS_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED,
++ get_default_directory_keep_aligned (),
++ keep_aligned);
++}
++
+ /* maintainence of auto layout boolean */
+ static gboolean default_directory_manual_layout = FALSE;
+
+@@ -880,6 +939,14 @@
+ }
+
+ static gboolean
++real_supports_keep_aligned (FMIconView *view)
++{
++ g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
++
++ return FALSE;
++}
++
++static gboolean
+ set_sort_reversed (FMIconView *icon_view, gboolean new_value)
+ {
+ if (icon_view->details->sort_reversed == new_value) {
+@@ -1005,6 +1072,9 @@
+ /* Set the sort direction from the metadata. */
+ set_sort_reversed (icon_view, fm_icon_view_get_directory_sort_reversed (icon_view, file));
+
++ nautilus_icon_container_set_keep_aligned
++ (get_icon_container (icon_view),
++ fm_icon_view_get_directory_keep_aligned (icon_view, file));
+ nautilus_icon_container_set_tighter_layout
+ (get_icon_container (icon_view),
+ fm_icon_view_get_directory_tighter_layout (icon_view, file));
+@@ -1287,6 +1357,37 @@
+ }
+
+ static void
++keep_aligned_state_changed_callback (BonoboUIComponent *component,
++ const char *path,
++ Bonobo_UIComponent_EventType type,
++ const char *state,
++ gpointer user_data)
++{
++ FMIconView *icon_view;
++ NautilusFile *file;
++ gboolean keep_aligned;
++
++ g_assert (strcmp (path, ID_KEEP_ALIGNED) == 0);
++
++ icon_view = FM_ICON_VIEW (user_data);
++
++ if (strcmp (state, "") == 0) {
++ /* State goes blank when component is removed; ignore this. */
++ return;
++ }
++
++ keep_aligned = strcmp (state, "1") == 0 ? TRUE : FALSE;
++
++ file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
++ fm_icon_view_set_directory_keep_aligned (icon_view,
++ file,
++ keep_aligned);
++
++ nautilus_icon_container_set_keep_aligned (get_icon_container (icon_view),
++ keep_aligned);
++}
++
++static void
+ switch_to_manual_layout (FMIconView *icon_view)
+ {
+ if (!fm_icon_view_using_auto_layout (icon_view)) {
+@@ -1393,6 +1494,7 @@
+
+ bonobo_ui_component_add_listener (icon_view->details->ui, ID_TIGHTER_LAYOUT, tighter_layout_state_changed_callback, view);
+ bonobo_ui_component_add_listener (icon_view->details->ui, ID_SORT_REVERSED, sort_reversed_state_changed_callback, view);
++ bonobo_ui_component_add_listener (icon_view->details->ui, ID_KEEP_ALIGNED, keep_aligned_state_changed_callback, view);
+ icon_view->details->menus_ready = TRUE;
+
+ bonobo_ui_component_freeze (icon_view->details->ui, NULL);
+@@ -1472,6 +1574,8 @@
+
+ set_sort_criterion (icon_view, get_sort_criterion_by_sort_type (get_default_sort_order ()));
+ set_sort_reversed (icon_view, get_default_sort_in_reverse_order ());
++ nautilus_icon_container_set_keep_aligned
++ (icon_container, get_default_directory_keep_aligned ());
+ nautilus_icon_container_set_tighter_layout
+ (icon_container, get_default_directory_tighter_layout ());
+
+@@ -2520,6 +2624,7 @@
+
+ klass->clean_up = fm_icon_view_real_clean_up;
+ klass->supports_auto_layout = real_supports_auto_layout;
++ klass->supports_keep_aligned = real_supports_keep_aligned;
+ klass->get_directory_auto_layout = fm_icon_view_real_get_directory_auto_layout;
+ klass->get_directory_sort_by = fm_icon_view_real_get_directory_sort_by;
+ klass->get_directory_sort_reversed = fm_icon_view_real_get_directory_sort_reversed;
+Index: src/file-manager/fm-icon-view.h
+===================================================================
+RCS file: /cvs/gnome/nautilus/src/file-manager/fm-icon-view.h,v
+retrieving revision 1.12
+diff -u -r1.12 fm-icon-view.h
+--- src/file-manager/fm-icon-view.h 4 Feb 2003 10:36:21 -0000 1.12
++++ src/file-manager/fm-icon-view.h 3 May 2003 23:21:43 -0000
+@@ -84,6 +84,12 @@
+ */
+ gboolean (* supports_auto_layout) (FMIconView *view);
+
++ /* supports_auto_layout is a function pointer that subclasses may
++ * override to control whether snap-to-grid mode
++ * should be enabled. The default implementation returns FALSE.
++ */
++ gboolean (* supports_keep_aligned) (FMIconView *view);
++
+ };
+
+ /* GObject support */
+Index: src/file-manager/nautilus-icon-view-ui.xml
+===================================================================
+RCS file: /cvs/gnome/nautilus/src/file-manager/nautilus-icon-view-ui.xml,v
+retrieving revision 1.23
+diff -u -r1.23 nautilus-icon-view-ui.xml
+--- src/file-manager/nautilus-icon-view-ui.xml 5 Jul 2002 20:37:24 -0000 1.23
++++ src/file-manager/nautilus-icon-view-ui.xml 3 May 2003 23:21:44 -0000
+@@ -24,6 +24,9 @@
+ <cmd name="Sort by Emblems"
+ _label="By _Emblems"
+ _tip="Keep icons sorted by emblems in rows"/>
++ <cmd name="Keep Aligned"
++ _label="_Keep Aligned"
++ _tip="Keep icons lined up on a grid"/>
+ <cmd name="Tighter Layout"
+ _label="Compact _Layout"
+ _tip="Toggle using a tighter layout scheme"/>
+@@ -78,6 +81,9 @@
+ </submenu>
+ <menuitem name="Clean Up"
+ verb="Clean Up"/>
++ <menuitem name="Keep Aligned"
++ id="Keep Aligned"
++ type="toggle"/>
+ </placeholder>
+
+ </submenu>
+@@ -108,6 +114,7 @@
+ id="Sort by Emblems"/>
+ </placeholder>
+ <separator/>
++
+ <menuitem name="Tighter Layout"
+ id="Tighter Layout"
+ type="toggle"/>
+@@ -115,7 +122,11 @@
+ id="Reversed Order"
+ type="toggle"/>
+ </submenu>
++
+ <menuitem name="Clean Up" verb="Clean Up"/>
++ <menuitem name="Keep Aligned"
++ id="Keep Aligned"
++ type="toggle"/>
+ </placeholder>
+ </placeholder>
+ </popup>