+ * gtk_icon_view_get_spacing:
+ * @icon_view: a #GtkIconView
+ *
+ * Returns the value of the ::spacing property.
+ *
+ * Return value: the space between cells
+ *
+ * Since: 2.6
+ */
+gint
+gtk_icon_view_get_spacing (GtkIconView *icon_view)
+{
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
+
+ return icon_view->priv->spacing;
+}
+
+/**
+ * gtk_icon_view_set_row_spacing:
+ * @icon_view: a #GtkIconView
+ * @row_spacing: the row spacing
+ *
+ * Sets the ::row-spacing property which specifies the space
+ * which is inserted between the rows of the icon view.
+ *
+ * Since: 2.6
+ */
+void
+gtk_icon_view_set_row_spacing (GtkIconView *icon_view,
+ gint row_spacing)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ if (icon_view->priv->row_spacing != row_spacing)
+ {
+ icon_view->priv->row_spacing = row_spacing;
+
+ gtk_icon_view_stop_editing (icon_view, TRUE);
+ gtk_icon_view_invalidate_sizes (icon_view);
+ gtk_icon_view_queue_layout (icon_view);
+
+ g_object_notify (G_OBJECT (icon_view), "row-spacing");
+ }
+}
+
+/**
+ * gtk_icon_view_get_row_spacing:
+ * @icon_view: a #GtkIconView
+ *
+ * Returns the value of the ::row-spacing property.
+ *
+ * Return value: the space between rows
+ *
+ * Since: 2.6
+ */
+gint
+gtk_icon_view_get_row_spacing (GtkIconView *icon_view)
+{
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
+
+ return icon_view->priv->row_spacing;
+}
+
+/**
+ * gtk_icon_view_set_column_spacing:
+ * @icon_view: a #GtkIconView
+ * @column_spacing: the column spacing
+ *
+ * Sets the ::column-spacing property which specifies the space
+ * which is inserted between the columns of the icon view.
+ *
+ * Since: 2.6
+ */
+void
+gtk_icon_view_set_column_spacing (GtkIconView *icon_view,
+ gint column_spacing)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ if (icon_view->priv->column_spacing != column_spacing)
+ {
+ icon_view->priv->column_spacing = column_spacing;
+
+ gtk_icon_view_stop_editing (icon_view, TRUE);
+ gtk_icon_view_invalidate_sizes (icon_view);
+ gtk_icon_view_queue_layout (icon_view);
+
+ g_object_notify (G_OBJECT (icon_view), "column-spacing");
+ }
+}
+
+/**
+ * gtk_icon_view_get_column_spacing:
+ * @icon_view: a #GtkIconView
+ *
+ * Returns the value of the ::column-spacing property.
+ *
+ * Return value: the space between columns
+ *
+ * Since: 2.6
+ */
+gint
+gtk_icon_view_get_column_spacing (GtkIconView *icon_view)
+{
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
+
+ return icon_view->priv->column_spacing;
+}
+
+/**
+ * gtk_icon_view_set_margin:
+ * @icon_view: a #GtkIconView
+ * @margin: the margin
+ *
+ * Sets the ::margin property which specifies the space
+ * which is inserted at the top, bottom, left and right
+ * of the icon view.
+ *
+ * Since: 2.6
+ */
+void
+gtk_icon_view_set_margin (GtkIconView *icon_view,
+ gint margin)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ if (icon_view->priv->margin != margin)
+ {
+ icon_view->priv->margin = margin;
+
+ gtk_icon_view_stop_editing (icon_view, TRUE);
+ gtk_icon_view_invalidate_sizes (icon_view);
+ gtk_icon_view_queue_layout (icon_view);
+
+ g_object_notify (G_OBJECT (icon_view), "margin");
+ }
+}
+
+/**
+ * gtk_icon_view_get_margin:
+ * @icon_view: a #GtkIconView
+ *
+ * Returns the value of the ::margin property.
+ *
+ * Return value: the space at the borders
+ *
+ * Since: 2.6
+ */
+gint
+gtk_icon_view_get_margin (GtkIconView *icon_view)
+{
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
+
+ return icon_view->priv->margin;
+}
+
+
+/* Get/set whether drag_motion requested the drag data and
+ * drag_data_received should thus not actually insert the data,
+ * since the data doesn't result from a drop.
+ */
+static void
+set_status_pending (GdkDragContext *context,
+ GdkDragAction suggested_action)
+{
+ g_object_set_data (G_OBJECT (context),
+ I_("gtk-icon-view-status-pending"),
+ GINT_TO_POINTER (suggested_action));
+}
+
+static GdkDragAction
+get_status_pending (GdkDragContext *context)
+{
+ return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
+ "gtk-icon-view-status-pending"));
+}
+
+static void
+unset_reorderable (GtkIconView *icon_view)
+{
+ if (icon_view->priv->reorderable)
+ {
+ icon_view->priv->reorderable = FALSE;
+ g_object_notify (G_OBJECT (icon_view), "reorderable");
+ }
+}
+
+static void
+clear_source_info (GtkIconView *icon_view)
+{
+ if (icon_view->priv->source_targets)
+ gtk_target_list_unref (icon_view->priv->source_targets);
+ icon_view->priv->source_targets = NULL;
+
+ icon_view->priv->source_set = FALSE;
+}
+
+static void
+clear_dest_info (GtkIconView *icon_view)
+{
+ if (icon_view->priv->dest_targets)
+ gtk_target_list_unref (icon_view->priv->dest_targets);
+ icon_view->priv->dest_targets = NULL;
+
+ icon_view->priv->dest_set = FALSE;
+}
+
+static void
+set_source_row (GdkDragContext *context,
+ GtkTreeModel *model,
+ GtkTreePath *source_row)
+{
+ if (source_row)
+ g_object_set_data_full (G_OBJECT (context),
+ I_("gtk-icon-view-source-row"),
+ gtk_tree_row_reference_new (model, source_row),
+ (GDestroyNotify) gtk_tree_row_reference_free);
+ else
+ g_object_set_data_full (G_OBJECT (context),
+ I_("gtk-icon-view-source-row"),
+ NULL, NULL);
+}
+
+static GtkTreePath*
+get_source_row (GdkDragContext *context)
+{
+ GtkTreeRowReference *ref;
+
+ ref = g_object_get_data (G_OBJECT (context), "gtk-icon-view-source-row");
+
+ if (ref)
+ return gtk_tree_row_reference_get_path (ref);
+ else
+ return NULL;
+}
+
+typedef struct
+{
+ GtkTreeRowReference *dest_row;
+ gboolean empty_view_drop;
+ gboolean drop_append_mode;
+} DestRow;
+
+static void
+dest_row_free (gpointer data)
+{
+ DestRow *dr = (DestRow *)data;
+
+ gtk_tree_row_reference_free (dr->dest_row);
+ g_free (dr);
+}
+
+static void
+set_dest_row (GdkDragContext *context,
+ GtkTreeModel *model,
+ GtkTreePath *dest_row,
+ gboolean empty_view_drop,
+ gboolean drop_append_mode)
+{
+ DestRow *dr;
+
+ if (!dest_row)
+ {
+ g_object_set_data_full (G_OBJECT (context),
+ I_("gtk-icon-view-dest-row"),
+ NULL, NULL);
+ return;
+ }
+
+ dr = g_new0 (DestRow, 1);
+
+ dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
+ dr->empty_view_drop = empty_view_drop;
+ dr->drop_append_mode = drop_append_mode;
+ g_object_set_data_full (G_OBJECT (context),
+ I_("gtk-icon-view-dest-row"),
+ dr, (GDestroyNotify) dest_row_free);
+}
+
+static GtkTreePath*
+get_dest_row (GdkDragContext *context)
+{
+ DestRow *dr;
+
+ dr = g_object_get_data (G_OBJECT (context), "gtk-icon-view-dest-row");
+
+ if (dr)
+ {
+ GtkTreePath *path = NULL;
+
+ if (dr->dest_row)
+ path = gtk_tree_row_reference_get_path (dr->dest_row);
+ else if (dr->empty_view_drop)
+ path = gtk_tree_path_new_from_indices (0, -1);
+ else
+ path = NULL;
+
+ if (path && dr->drop_append_mode)
+ gtk_tree_path_next (path);
+
+ return path;
+ }
+ else
+ return NULL;
+}
+
+static gboolean
+check_model_dnd (GtkTreeModel *model,
+ GType required_iface,
+ const gchar *signal)
+{
+ if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
+ {
+ g_warning ("You must override the default '%s' handler "
+ "on GtkIconView when using models that don't support "
+ "the %s interface and enabling drag-and-drop. The simplest way to do this "
+ "is to connect to '%s' and call "
+ "g_signal_stop_emission_by_name() in your signal handler to prevent "
+ "the default handler from running. Look at the source code "
+ "for the default handler in gtkiconview.c to get an idea what "
+ "your handler should do. (gtkiconview.c is in the GTK+ source "
+ "code.) If you're using GTK+ from a language other than C, "
+ "there may be a more natural way to override default handlers, e.g. via derivation.",
+ signal, g_type_name (required_iface), signal);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+static void
+remove_scroll_timeout (GtkIconView *icon_view)
+{
+ if (icon_view->priv->scroll_timeout_id != 0)
+ {
+ g_source_remove (icon_view->priv->scroll_timeout_id);
+
+ icon_view->priv->scroll_timeout_id = 0;
+ }
+}
+
+static void
+gtk_icon_view_autoscroll (GtkIconView *icon_view)
+{
+ gint px, py, x, y, width, height;
+ gint hoffset, voffset;
+ gfloat value;
+
+ gdk_window_get_pointer (GTK_WIDGET (icon_view)->window, &px, &py, NULL);
+ gdk_window_get_geometry (GTK_WIDGET (icon_view)->window, &x, &y, &width, &height, NULL);
+
+ /* see if we are near the edge. */
+ voffset = py - (y + 2 * SCROLL_EDGE_SIZE);
+ if (voffset > 0)
+ voffset = MAX (py - (y + height - 2 * SCROLL_EDGE_SIZE), 0);
+
+ hoffset = px - (x + 2 * SCROLL_EDGE_SIZE);
+ if (hoffset > 0)
+ hoffset = MAX (px - (x + width - 2 * SCROLL_EDGE_SIZE), 0);
+
+ if (voffset != 0)
+ {
+ value = CLAMP (icon_view->priv->vadjustment->value + voffset,
+ icon_view->priv->vadjustment->lower,
+ icon_view->priv->vadjustment->upper - icon_view->priv->vadjustment->page_size);
+ gtk_adjustment_set_value (icon_view->priv->vadjustment, value);
+ }
+ if (hoffset != 0)
+ {
+ value = CLAMP (icon_view->priv->hadjustment->value + hoffset,
+ icon_view->priv->hadjustment->lower,
+ icon_view->priv->hadjustment->upper - icon_view->priv->hadjustment->page_size);
+ gtk_adjustment_set_value (icon_view->priv->hadjustment, value);
+ }
+}
+
+
+static gboolean
+drag_scroll_timeout (gpointer data)
+{
+ GtkIconView *icon_view = GTK_ICON_VIEW (data);
+
+ GDK_THREADS_ENTER ();
+
+ gtk_icon_view_autoscroll (icon_view);
+
+ GDK_THREADS_LEAVE ();
+
+ return TRUE;
+}
+
+
+static gboolean
+set_destination (GtkIconView *icon_view,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GdkDragAction *suggested_action,
+ GdkAtom *target)
+{
+ GtkWidget *widget;
+ GtkTreePath *path = NULL;
+ GtkIconViewDropPosition pos;
+ GtkIconViewDropPosition old_pos;
+ GtkTreePath *old_dest_path = NULL;
+ gboolean can_drop = FALSE;
+
+ widget = GTK_WIDGET (icon_view);
+
+ *suggested_action = 0;
+ *target = GDK_NONE;
+
+ if (!icon_view->priv->dest_set)
+ {
+ /* someone unset us as a drag dest, note that if
+ * we return FALSE drag_leave isn't called
+ */
+
+ gtk_icon_view_set_drag_dest_item (icon_view,
+ NULL,
+ GTK_ICON_VIEW_DROP_LEFT);
+
+ remove_scroll_timeout (GTK_ICON_VIEW (widget));
+
+ return FALSE; /* no longer a drop site */
+ }
+
+ *target = gtk_drag_dest_find_target (widget, context, icon_view->priv->dest_targets);
+ if (*target == GDK_NONE)
+ return FALSE;
+
+ if (!gtk_icon_view_get_dest_item_at_pos (icon_view, x, y, &path, &pos))
+ {
+ gint n_children;
+ GtkTreeModel *model;
+
+ /* the row got dropped on empty space, let's setup a special case
+ */
+
+ if (path)
+ gtk_tree_path_free (path);
+
+ model = gtk_icon_view_get_model (icon_view);
+
+ n_children = gtk_tree_model_iter_n_children (model, NULL);
+ if (n_children)
+ {
+ pos = GTK_ICON_VIEW_DROP_BELOW;
+ path = gtk_tree_path_new_from_indices (n_children - 1, -1);
+ }
+ else
+ {
+ pos = GTK_ICON_VIEW_DROP_ABOVE;
+ path = gtk_tree_path_new_from_indices (0, -1);
+ }
+
+ can_drop = TRUE;
+
+ goto out;
+ }
+
+ g_assert (path);
+
+ gtk_icon_view_get_drag_dest_item (icon_view,
+ &old_dest_path,
+ &old_pos);
+
+ if (old_dest_path)
+ gtk_tree_path_free (old_dest_path);
+
+ if (TRUE /* FIXME if the location droppable predicate */)
+ {
+ can_drop = TRUE;
+ }
+
+out:
+ if (can_drop)
+ {
+ GtkWidget *source_widget;
+
+ *suggested_action = context->suggested_action;
+ source_widget = gtk_drag_get_source_widget (context);
+
+ if (source_widget == widget)
+ {
+ /* Default to MOVE, unless the user has
+ * pressed ctrl or shift to affect available actions
+ */
+ if ((context->actions & GDK_ACTION_MOVE) != 0)
+ *suggested_action = GDK_ACTION_MOVE;
+ }
+
+ gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
+ path, pos);
+ }
+ else
+ {
+ /* can't drop here */
+ gtk_icon_view_set_drag_dest_item (GTK_ICON_VIEW (widget),
+ NULL,
+ GTK_ICON_VIEW_DROP_LEFT);
+ }
+
+ if (path)
+ gtk_tree_path_free (path);
+
+ return TRUE;
+}
+
+static GtkTreePath*
+get_logical_destination (GtkIconView *icon_view,
+ gboolean *drop_append_mode)
+{
+ /* adjust path to point to the row the drop goes in front of */
+ GtkTreePath *path = NULL;
+ GtkIconViewDropPosition pos;
+
+ *drop_append_mode = FALSE;
+
+ gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
+
+ if (path == NULL)
+ return NULL;
+
+ if (pos == GTK_ICON_VIEW_DROP_RIGHT ||
+ pos == GTK_ICON_VIEW_DROP_BELOW)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel *model = icon_view->priv->model;
+
+ if (!gtk_tree_model_get_iter (model, &iter, path) ||
+ !gtk_tree_model_iter_next (model, &iter))
+ *drop_append_mode = TRUE;
+ else
+ {
+ *drop_append_mode = FALSE;
+ gtk_tree_path_next (path);
+ }
+ }
+
+ return path;
+}
+
+static gboolean
+gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
+ GdkEventMotion *event)
+{
+ GdkDragContext *context;
+ GtkTreePath *path = NULL;
+ gint button;
+ GtkTreeModel *model;
+ gboolean retval = FALSE;
+
+ if (!icon_view->priv->source_set)
+ goto out;
+
+ if (icon_view->priv->pressed_button < 0)
+ goto out;
+
+ if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
+ icon_view->priv->press_start_x,
+ icon_view->priv->press_start_y,
+ event->x, event->y))
+ goto out;
+
+ model = gtk_icon_view_get_model (icon_view);
+
+ if (model == NULL)
+ goto out;
+
+ button = icon_view->priv->pressed_button;
+ icon_view->priv->pressed_button = -1;
+
+ path = gtk_icon_view_get_path_at_pos (icon_view,
+ icon_view->priv->press_start_x,
+ icon_view->priv->press_start_y);
+
+ if (path == NULL)
+ goto out;
+
+ if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
+ !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
+ path))
+ goto out;
+
+ /* FIXME Check whether we're a start button, if not return FALSE and
+ * free path
+ */
+
+ /* Now we can begin the drag */
+
+ retval = TRUE;
+
+ context = gtk_drag_begin (GTK_WIDGET (icon_view),
+ icon_view->priv->source_targets,
+ icon_view->priv->source_actions,
+ button,
+ (GdkEvent*)event);
+
+ set_source_row (context, model, path);
+
+ out:
+ if (path)
+ gtk_tree_path_free (path);
+
+ return retval;
+}
+
+/* Source side drag signals */
+static void
+gtk_icon_view_drag_begin (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GtkIconView *icon_view;
+ GtkIconViewItem *item;
+ GdkPixmap *icon;
+ gint x, y;
+ GtkTreePath *path;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+ /* if the user uses a custom DnD impl, we don't set the icon here */
+ if (!icon_view->priv->dest_set && !icon_view->priv->source_set)
+ return;
+
+ item = gtk_icon_view_get_item_at_coords (icon_view,
+ icon_view->priv->press_start_x,
+ icon_view->priv->press_start_y,
+ TRUE,
+ NULL);
+
+ g_return_if_fail (item != NULL);
+
+ x = icon_view->priv->press_start_x - item->x + 1;
+ y = icon_view->priv->press_start_y - item->y + 1;
+
+ path = gtk_tree_path_new_from_indices (item->index, -1);
+ icon = gtk_icon_view_create_drag_icon (icon_view, path);
+ gtk_tree_path_free (path);
+
+ gtk_drag_set_icon_pixmap (context,
+ gdk_drawable_get_colormap (icon),
+ icon,
+ NULL,
+ x, y);
+
+ g_object_unref (icon);
+}
+
+static void
+gtk_icon_view_drag_end (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ /* do nothing */
+}
+
+static void
+gtk_icon_view_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ GtkIconView *icon_view;
+ GtkTreeModel *model;
+ GtkTreePath *source_row;
+
+ icon_view = GTK_ICON_VIEW (widget);
+ model = gtk_icon_view_get_model (icon_view);
+
+ if (model == NULL)
+ return;
+
+ if (!icon_view->priv->dest_set)
+ return;
+
+ source_row = get_source_row (context);
+
+ if (source_row == NULL)
+ return;
+
+ /* We can implement the GTK_TREE_MODEL_ROW target generically for
+ * any model; for DragSource models there are some other targets
+ * we also support.
+ */
+
+ if (GTK_IS_TREE_DRAG_SOURCE (model) &&
+ gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
+ source_row,
+ selection_data))
+ goto done;
+
+ /* If drag_data_get does nothing, try providing row data. */
+ if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
+ gtk_tree_set_row_drag_data (selection_data,
+ model,
+ source_row);
+
+ done:
+ gtk_tree_path_free (source_row);
+}
+
+static void
+gtk_icon_view_drag_data_delete (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GtkTreeModel *model;
+ GtkIconView *icon_view;
+ GtkTreePath *source_row;
+
+ icon_view = GTK_ICON_VIEW (widget);
+ model = gtk_icon_view_get_model (icon_view);
+
+ if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
+ return;
+
+ if (!icon_view->priv->dest_set)
+ return;
+
+ source_row = get_source_row (context);
+
+ if (source_row == NULL)
+ return;
+
+ gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
+ source_row);
+
+ gtk_tree_path_free (source_row);
+
+ set_source_row (context, NULL, NULL);
+}
+
+/* Target side drag signals */
+static void
+gtk_icon_view_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time)
+{
+ GtkIconView *icon_view;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+ /* unset any highlight row */
+ gtk_icon_view_set_drag_dest_item (icon_view,
+ NULL,
+ GTK_ICON_VIEW_DROP_LEFT);
+
+ remove_scroll_timeout (icon_view);
+}
+
+static gboolean
+gtk_icon_view_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GtkTreePath *path = NULL;
+ GtkIconViewDropPosition pos;
+ GtkIconView *icon_view;
+ GdkDragAction suggested_action = 0;
+ GdkAtom target;
+ gboolean empty;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+ if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
+ return FALSE;
+
+ gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
+
+ /* we only know this *after* set_desination_row */
+ empty = icon_view->priv->empty_view_drop;
+
+ if (path == NULL && !empty)
+ {
+ /* Can't drop here. */
+ gdk_drag_status (context, 0, time);
+ }
+ else
+ {
+ if (icon_view->priv->scroll_timeout_id == 0)
+ {
+ icon_view->priv->scroll_timeout_id =
+ g_timeout_add (50, drag_scroll_timeout, icon_view);
+ }
+
+ if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
+ {
+ /* Request data so we can use the source row when
+ * determining whether to accept the drop
+ */
+ set_status_pending (context, suggested_action);
+ gtk_drag_get_data (widget, context, target, time);
+ }
+ else
+ {
+ set_status_pending (context, 0);
+ gdk_drag_status (context, suggested_action, time);
+ }
+ }
+
+ if (path)
+ gtk_tree_path_free (path);
+
+ return TRUE;
+}
+
+static gboolean
+gtk_icon_view_drag_drop (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GtkIconView *icon_view;
+ GtkTreePath *path;
+ GdkDragAction suggested_action = 0;
+ GdkAtom target = GDK_NONE;
+ GtkTreeModel *model;
+ gboolean drop_append_mode;
+
+ icon_view = GTK_ICON_VIEW (widget);
+ model = gtk_icon_view_get_model (icon_view);
+
+ remove_scroll_timeout (GTK_ICON_VIEW (widget));
+
+ if (!icon_view->priv->dest_set)
+ return FALSE;
+
+ if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
+ return FALSE;
+
+ if (!set_destination (icon_view, context, x, y, &suggested_action, &target))
+ return FALSE;
+
+ path = get_logical_destination (icon_view, &drop_append_mode);
+
+ if (target != GDK_NONE && path != NULL)
+ {
+ /* in case a motion had requested drag data, change things so we
+ * treat drag data receives as a drop.
+ */
+ set_status_pending (context, 0);
+ set_dest_row (context, model, path,
+ icon_view->priv->empty_view_drop, drop_append_mode);
+ }
+
+ if (path)
+ gtk_tree_path_free (path);
+
+ /* Unset this thing */
+ gtk_icon_view_set_drag_dest_item (icon_view, NULL, GTK_ICON_VIEW_DROP_LEFT);
+
+ if (target != GDK_NONE)
+ {
+ gtk_drag_get_data (widget, context, target, time);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static void
+gtk_icon_view_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ GtkTreePath *path;
+ gboolean accepted = FALSE;
+ GtkTreeModel *model;
+ GtkIconView *icon_view;
+ GtkTreePath *dest_row;
+ GdkDragAction suggested_action;
+ gboolean drop_append_mode;
+
+ icon_view = GTK_ICON_VIEW (widget);
+ model = gtk_icon_view_get_model (icon_view);
+
+ if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
+ return;
+
+ if (!icon_view->priv->dest_set)
+ return;
+
+ suggested_action = get_status_pending (context);
+
+ if (suggested_action)
+ {
+ /* We are getting this data due to a request in drag_motion,
+ * rather than due to a request in drag_drop, so we are just
+ * supposed to call drag_status, not actually paste in the
+ * data.
+ */
+ path = get_logical_destination (icon_view, &drop_append_mode);
+
+ if (path == NULL)
+ suggested_action = 0;
+
+ if (suggested_action)
+ {
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ path,
+ selection_data))
+ suggested_action = 0;
+ }
+
+ gdk_drag_status (context, suggested_action, time);
+
+ if (path)
+ gtk_tree_path_free (path);
+
+ /* If you can't drop, remove user drop indicator until the next motion */
+ if (suggested_action == 0)
+ gtk_icon_view_set_drag_dest_item (icon_view,
+ NULL,
+ GTK_ICON_VIEW_DROP_LEFT);
+ return;
+ }
+
+
+ dest_row = get_dest_row (context);
+
+ if (dest_row == NULL)
+ return;
+
+ if (selection_data->length >= 0)
+ {
+ if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
+ dest_row,
+ selection_data))
+ accepted = TRUE;
+ }
+
+ gtk_drag_finish (context,
+ accepted,
+ (context->action == GDK_ACTION_MOVE),
+ time);
+
+ gtk_tree_path_free (dest_row);
+
+ /* drop dest_row */
+ set_dest_row (context, NULL, NULL, FALSE, FALSE);
+}
+
+/* Drag-and-Drop support */
+/**
+ * gtk_icon_view_enable_model_drag_source:
+ * @icon_view: a #GtkIconTreeView
+ * @start_button_mask: Mask of allowed buttons to start drag
+ * @targets: the table of targets that the drag will support
+ * @n_targets: the number of items in @targets
+ * @actions: the bitmask of possible actions for a drag from this
+ * widget
+ *
+ * Turns @icon_view into a drag source for automatic DND.
+ *
+ * Since: 2.8
+ **/
+void
+gtk_icon_view_enable_model_drag_source (GtkIconView *icon_view,
+ GdkModifierType start_button_mask,
+ const GtkTargetEntry *targets,
+ gint n_targets,
+ GdkDragAction actions)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ gtk_drag_source_set (GTK_WIDGET (icon_view), 0, NULL, 0, actions);
+
+ clear_source_info (icon_view);
+ icon_view->priv->start_button_mask = start_button_mask;
+ icon_view->priv->source_targets = gtk_target_list_new (targets, n_targets);
+ icon_view->priv->source_actions = actions;
+
+ icon_view->priv->source_set = TRUE;
+
+ unset_reorderable (icon_view);
+}
+
+/**
+ * gtk_icon_view_enable_model_drag_dest:
+ * @icon_view: a #GtkIconView
+ * @targets: the table of targets that the drag will support
+ * @n_targets: the number of items in @targets
+ * @actions: the bitmask of possible actions for a drag to this
+ * widget
+ *
+ * Turns @icon_view into a drop destination for automatic DND.
+ *
+ * Since: 2.8
+ **/
+void
+gtk_icon_view_enable_model_drag_dest (GtkIconView *icon_view,
+ const GtkTargetEntry *targets,
+ gint n_targets,
+ GdkDragAction actions)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ gtk_drag_dest_set (GTK_WIDGET (icon_view), 0, NULL, 0, actions);
+
+ clear_dest_info (icon_view);
+
+ icon_view->priv->dest_targets = gtk_target_list_new (targets, n_targets);
+ icon_view->priv->dest_actions = actions;
+
+ icon_view->priv->dest_set = TRUE;
+
+ unset_reorderable (icon_view);
+}
+
+/**
+ * gtk_icon_view_unset_model_drag_source:
+ * @icon_view: a #GtkIconView
+ *
+ * Undoes the effect of gtk_icon_view_enable_model_drag_source().
+ *
+ * Since: 2.8
+ **/
+void
+gtk_icon_view_unset_model_drag_source (GtkIconView *icon_view)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ if (icon_view->priv->source_set)
+ {
+ gtk_drag_source_unset (GTK_WIDGET (icon_view));
+ clear_source_info (icon_view);
+ }
+
+ unset_reorderable (icon_view);
+}
+
+/**
+ * gtk_icon_view_unset_model_drag_dest: