view src/dnd.c @ 8:e0d0593d519e

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:07:07 +0000
parents c0e337a01cb7
children d907d608745f
line wrap: on
line source

/*
 * GQview image viewer
 * (C)2000 John Ellis
 *
 * Author: John Ellis
 *
 */

#include "gqview.h"
#include "image.h"

enum {
	TARGET_URI_LIST,
	TARGET_TEXT_PLAIN
};

static GtkTargetEntry file_drag_types[] = {
	{ "text/uri-list", 0, TARGET_URI_LIST },
	{ "text/plain", 0, TARGET_TEXT_PLAIN }
};
static gint n_file_drag_types = 2;

static GtkTargetEntry file_drop_types[] = {
	{ "text/uri-list", 0, TARGET_URI_LIST }
};
static gint n_file_drop_types = 1;

static GList *get_uri_file_list(gchar *data);

static void image_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
			       gint x, gint y,
			       GtkSelectionData *selection_data, guint info,
			       guint time, gpointer data);
static void image_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
			      GtkSelectionData *selection_data, guint info,
			      guint time, gpointer data);
static void image_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data);

static void file_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
			      GtkSelectionData *selection_data, guint info,
			      guint time, gpointer data);
static void file_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data);
static void file_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data);

static void dir_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
			      GtkSelectionData *selection_data, guint info,
			      guint time, gpointer data);
static void dir_clist_set_highlight(gint set);
static void dir_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data);
static void dir_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data);

static GList *get_uri_file_list(gchar *data)
{
	GList *list = NULL;
	gint b, e;

	b = e = 0;

	while (data[b] != '\0')
		{
		while (data[e] != '\r' && data[e] != '\n' && data[e] != '\0') e++;
		if (!strncmp(data + b, "file:", 5))
			{
			b += 5;
			list = g_list_append(list, g_strndup(data + b, e - b));
			}
		while (data[e] == '\r' || data[e] == '\n') e++;
		b = e;
		}

	return list;
}

/*
 *-----------------------------------------------------------------------------
 * image drag and drop routines
 *-----------------------------------------------------------------------------
 */ 

static void image_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
			       gint x, gint y,
			       GtkSelectionData *selection_data, guint info,
			       guint time, gpointer data)
{
	ImageWindow *imd = data;

	if (info == TARGET_URI_LIST)
		{
		GList *list = get_uri_file_list(selection_data->data);
		if (list)
			{
			gchar *path;

			path = list->data;

			if (imd == normal_image)
				{
				if (isfile(path))
					{
					gint row;
					gchar *dir = remove_level_from_path(path);
					if (strcmp(dir, current_path) != 0)
						filelist_change_to(dir);
					g_free(dir);
	
					row = find_file_in_list(path);
					if (row == -1)
						image_change_to(path);
					else
						file_image_change_to(row);
					}
				else if (isdir(path))
					{
					filelist_change_to(path);
					image_change_to(NULL);
					}
				}
			else
				{
				if (isfile(path))
					{
					image_area_set_image(imd, path, get_default_zoom(imd));
					}
				}

			if (debug)
				{
				GList *work = list;
				while (work)
					{
					printf("dropped: %s\n", (gchar *)(work->data));
					work = work->next;
					}
				}

			g_list_foreach(list, (GFunc)g_free, NULL);
			g_list_free(list);
			}
		}
}

static void image_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
			       GtkSelectionData *selection_data, guint info,
			       guint time, gpointer data)
{
	ImageWindow *imd = data;
	gchar *path = image_area_get_path(imd);

	if (path)
		{
		gchar *text = NULL;
		switch (info)
			{
			case TARGET_URI_LIST:
				text = g_strconcat("file:", path, "\r\n", NULL);
				break;
			case TARGET_TEXT_PLAIN:
				text = g_strdup(path);
				break;
			}
		if (text)
			{
			gtk_selection_data_set (selection_data, selection_data->target,
						8, text, strlen(text));
			g_free(text);
			}
		}
	else
		{
		gtk_selection_data_set (selection_data, selection_data->target,
					8, NULL, 0);
		}
}

static void image_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
	ImageWindow *imd = data;
	if (context->action == GDK_ACTION_MOVE)
		{
		gint row = find_file_in_list(image_area_get_path(imd));
		if (row < 0) return;
		if (image_get_path() && strcmp(image_get_path(), image_area_get_path(imd)) == 0)
			{
			if (row < file_count() - 1)
				{
				file_next_image();
				}
			else
				{
				file_prev_image();
				}
			}
		filelist_refresh();
		}
}

void image_dnd_init(ImageWindow *imd)
{
	gtk_drag_source_set(imd->viewport, GDK_BUTTON2_MASK,
				file_drag_types, n_file_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
	gtk_signal_connect(GTK_OBJECT(imd->viewport), "drag_data_get",
				image_set_dnd_data, imd);
	gtk_signal_connect(GTK_OBJECT(imd->viewport), "drag_end",
				image_drag_end, imd);

	gtk_drag_dest_set(imd->viewport,
			  GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
			  file_drop_types, n_file_drop_types,
                          GDK_ACTION_COPY);
	gtk_signal_connect(GTK_OBJECT(imd->viewport), "drag_data_received",
				image_get_dnd_data, imd);
}

/*
 *-----------------------------------------------------------------------------
 * file list drag and drop routines (private)
 *-----------------------------------------------------------------------------
 */ 

static void file_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
			      GtkSelectionData *selection_data, guint info,
			      guint time, gpointer data)
{
	gchar *uri_text = NULL;
	gchar *leader = "file:";
	gchar *sep = "\r\n";
	gint total;
	gint leader_l;
	gint sep_l = strlen(sep);
	gchar *ptr;

	switch (info)
		{
		case TARGET_URI_LIST:
			leader_l = strlen(leader);
			break;
		case TARGET_TEXT_PLAIN:
			leader_l = 0;
			break;
		default:
			return;
			break;
		}
	
	if (file_clicked_is_selected())
		{
		GList *list;
		GList *work;

		list = file_get_selected_list();
		if (!list) return;
		work = list;
		total = 0;

		/* compute length */

		while (work)
			{
			gchar *name = work->data;
			total += leader_l + strlen(name) + sep_l;
			work = work->next;
			}

		/* create list */
		uri_text = g_malloc(total + 1);
		ptr = uri_text;

		work = list;
		while (work)
			{
			gchar *name = work->data;
			if (leader_l > 0)
				{
				strcpy(ptr, leader);
				ptr += leader_l;
				}
			strcpy(ptr, name);
			ptr += strlen(name);
			strcpy(ptr, sep);
			ptr += sep_l;
			work = work->next;
			}
		ptr[0] = '\0';
		free_selected_list(list);
		}
	else
		{
		gchar *path = file_clicked_get_path();
		if (!path) return;
		switch (info)
			{
			case TARGET_URI_LIST:
				uri_text = g_strconcat("file:", path, "\r\n", NULL);
				break;
			case TARGET_TEXT_PLAIN:
				uri_text = g_strdup(path);
				break;
			}
		total = strlen(uri_text);
		g_free(path);
		}

	if (debug) printf(uri_text);

	gtk_selection_data_set (selection_data, selection_data->target,
					8, uri_text, total);
	g_free(uri_text);

	file_clist_highlight_unset();
}

static void file_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
	file_clist_highlight_set();
}

static void file_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
	file_clist_highlight_unset();

	if (context->action == GDK_ACTION_MOVE)
		{
		filelist_refresh();
		}
}

/*
 *-----------------------------------------------------------------------------
 * directory list drag and drop routines (private)
 *-----------------------------------------------------------------------------
 */ 

static void dir_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
			      GtkSelectionData *selection_data, guint info,
			      guint time, gpointer data)
{
	gint row = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(dir_clist)));

	if (row >= 0)
		{
		gchar *name = gtk_clist_get_row_data(GTK_CLIST(dir_clist), row);
		gchar *new_path;
		gchar *text = NULL;

		if (strcmp(name, ".") == 0)
			new_path = g_strdup(current_path);
		else if (strcmp(name, "..") == 0)
			new_path = remove_level_from_path(current_path);
		else
			{
			if (strcmp(current_path, "/") == 0)
				new_path = g_strconcat(current_path, name, NULL);
			else
				new_path = g_strconcat(current_path, "/", name, NULL);
			}

		
		switch (info)
			{
			case TARGET_URI_LIST:
				text = g_strconcat("file:", new_path, "\r\n", NULL);
				break;
			case TARGET_TEXT_PLAIN:
				text = g_strdup(new_path);
				break;
			}
		if (text)
			{
			gtk_selection_data_set (selection_data, selection_data->target,
					8, text, strlen(text));
			g_free(text);
			}
		g_free(new_path);
		}
}

static void dir_clist_set_highlight(gint set)
{
	gint row = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(dir_clist)));
	if (set)
		{
		gtk_clist_set_background(GTK_CLIST(dir_clist), row,
			&GTK_WIDGET (dir_clist)->style->bg[GTK_STATE_SELECTED]);
		gtk_clist_set_foreground(GTK_CLIST(dir_clist), row,
			&GTK_WIDGET (dir_clist)->style->fg[GTK_STATE_SELECTED]);
		}
	else
		{
		gtk_clist_set_background(GTK_CLIST(dir_clist), row, NULL);
		gtk_clist_set_foreground(GTK_CLIST(dir_clist), row, NULL);
		}
}

static void dir_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
	dir_clist_set_highlight(TRUE);
}

static void dir_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
	dir_clist_set_highlight(FALSE);

	if (context->action == GDK_ACTION_MOVE)
		{
		filelist_refresh();
		}
}

/*
 *-----------------------------------------------------------------------------
 * drag and drop initialization (public)
 *-----------------------------------------------------------------------------
 */ 

void init_dnd()
{
	/* dir clist */
	gtk_drag_source_set(dir_clist, GDK_BUTTON2_MASK,
				file_drag_types, n_file_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
	gtk_signal_connect(GTK_OBJECT(dir_clist), "drag_begin",
				dir_list_drag_begin, NULL);
	gtk_signal_connect(GTK_OBJECT(dir_clist), "drag_data_get",
				dir_list_set_dnd_data, NULL);
	gtk_signal_connect(GTK_OBJECT(dir_clist), "drag_end",
				dir_list_drag_end, NULL);

	/* file clist */
	gtk_drag_source_set(file_clist, GDK_BUTTON2_MASK,
				file_drag_types, n_file_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
	gtk_signal_connect(GTK_OBJECT(file_clist), "drag_begin",
				file_list_drag_begin, NULL);
	gtk_signal_connect(GTK_OBJECT(file_clist), "drag_data_get",
				file_list_set_dnd_data, NULL);
	gtk_signal_connect(GTK_OBJECT(file_clist), "drag_end",
				file_list_drag_end, NULL);

	/* image */
	image_dnd_init(main_image);
}