static void
slot_proxy_drag_data_received (GtkWidget          *widget,
                               GdkDragContext     *context,
                               int                 x,
                               int                 y,
                               GtkSelectionData   *data,
                               unsigned int        info,
                               unsigned int        time,
                               gpointer            user_data)
{
    NautilusDragSlotProxyInfo *drag_info;
    char **uris;

    drag_info = user_data;

    g_assert (!drag_info->have_data);

    drag_info->have_data = TRUE;
    drag_info->info = info;

    if (gtk_selection_data_get_length (data) < 0) {
        drag_info->have_valid_data = FALSE;
        return;
    }

    if (info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
        drag_info->data.selection_list = nautilus_drag_build_selection_list (data);

        drag_info->have_valid_data = drag_info->data.selection_list != NULL;
    } else if (info == NAUTILUS_ICON_DND_URI_LIST) {
        uris = gtk_selection_data_get_uris (data);
        drag_info->data.uri_list = nautilus_drag_uri_list_from_array ((const char **) uris);
        g_strfreev (uris);

        drag_info->have_valid_data = drag_info->data.uri_list != NULL;
    } else if (info == NAUTILUS_ICON_DND_NETSCAPE_URL) {
        drag_info->data.netscape_url = g_strdup ((char *) gtk_selection_data_get_data (data));

        drag_info->have_valid_data = drag_info->data.netscape_url != NULL;
    } else if (info == NAUTILUS_ICON_DND_TEXT ||
               info == NAUTILUS_ICON_DND_XDNDDIRECTSAVE ||
               info == NAUTILUS_ICON_DND_RAW) {
        drag_info->data.selection_data = gtk_selection_data_copy (data);
        drag_info->have_valid_data = drag_info->data.selection_data != NULL;
    }

    if (drag_info->drop_occured) {
        slot_proxy_handle_drop (widget, context, time, drag_info);
    }
}
static gboolean
drag_data_received_callback (GtkWidget *widget,
                             GdkDragContext *context,
                             int x,
                             int y,
                             GtkSelectionData *selection_data,
                             guint info,
                             guint32 time,
                             gpointer data)
{
    NautilusTreeViewDragDest *dest;
    const gchar *tmp;
    int length;
    gboolean success, finished;

    dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data);

    if (!dest->details->have_drag_data) {
        dest->details->have_drag_data = TRUE;
        dest->details->drag_type = info;
        dest->details->drag_data =
            gtk_selection_data_copy (selection_data);
        if (info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
            dest->details->drag_list =
                nautilus_drag_build_selection_list (selection_data);
        }
    }

    if (dest->details->drop_occurred) {
        success = FALSE;
        finished = TRUE;
        switch (info) {
        case NAUTILUS_ICON_DND_GNOME_ICON_LIST :
            receive_dropped_icons (dest, context, x, y);
            success = TRUE;
            break;
        case NAUTILUS_ICON_DND_NETSCAPE_URL :
            receive_dropped_netscape_url (dest, context, x, y);
            success = TRUE;
            break;
        case NAUTILUS_ICON_DND_URI_LIST :
            receive_dropped_uri_list (dest, context, x, y);
            success = TRUE;
            break;
        case NAUTILUS_ICON_DND_TEXT:
            receive_dropped_text (dest, context, x, y);
            success = TRUE;
            break;
        case NAUTILUS_ICON_DND_RAW:
            length = gtk_selection_data_get_length (selection_data);
            tmp = (const gchar *) gtk_selection_data_get_data (selection_data);
            receive_dropped_raw (dest, tmp, length, context, x, y);
            success = TRUE;
            break;
        case NAUTILUS_ICON_DND_XDNDDIRECTSAVE:
            finished = receive_xds (dest, widget, time, context, x, y);
            success = TRUE;
            break;
        }

        if (finished) {
            dest->details->drop_occurred = FALSE;
            free_drag_data (dest);
            gtk_drag_finish (context, success, FALSE, time);
        }
    }

    /* appease GtkTreeView by preventing its drag_data_receive
     * from being called */
    g_signal_stop_emission_by_name (dest->details->tree_view,
                                    "drag-data-received");

    return TRUE;
}