0.8.0
[geeqie.git] / src / dnd.c
1 /*
2  * GQview image viewer
3  * (C)2000 John Ellis
4  *
5  * Author: John Ellis
6  *
7  */
8
9 #include "gqview.h"
10 #include "image.h"
11
12 enum {
13         TARGET_URI_LIST,
14         TARGET_TEXT_PLAIN
15 };
16
17 static GtkTargetEntry file_drag_types[] = {
18         { "text/uri-list", 0, TARGET_URI_LIST },
19         { "text/plain", 0, TARGET_TEXT_PLAIN }
20 };
21 static gint n_file_drag_types = 2;
22
23 static GtkTargetEntry file_drop_types[] = {
24         { "text/uri-list", 0, TARGET_URI_LIST }
25 };
26 static gint n_file_drop_types = 1;
27
28 static GList *get_uri_file_list(gchar *data);
29
30 static void image_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
31                                gint x, gint y,
32                                GtkSelectionData *selection_data, guint info,
33                                guint time, gpointer data);
34 static void image_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
35                               GtkSelectionData *selection_data, guint info,
36                               guint time, gpointer data);
37 static void image_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data);
38
39 static void file_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
40                               GtkSelectionData *selection_data, guint info,
41                               guint time, gpointer data);
42 static void file_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data);
43 static void file_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data);
44
45 static void dir_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
46                               GtkSelectionData *selection_data, guint info,
47                               guint time, gpointer data);
48 static void dir_clist_set_highlight(gint set);
49 static void dir_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data);
50 static void dir_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data);
51
52 static GList *get_uri_file_list(gchar *data)
53 {
54         GList *list = NULL;
55         gint b, e;
56
57         b = e = 0;
58
59         while (data[b] != '\0')
60                 {
61                 while (data[e] != '\r' && data[e] != '\n' && data[e] != '\0') e++;
62                 if (!strncmp(data + b, "file:", 5))
63                         {
64                         b += 5;
65                         list = g_list_append(list, g_strndup(data + b, e - b));
66                         }
67                 while (data[e] == '\r' || data[e] == '\n') e++;
68                 b = e;
69                 }
70
71         return list;
72 }
73
74 /*
75  *-----------------------------------------------------------------------------
76  * image drag and drop routines
77  *-----------------------------------------------------------------------------
78  */ 
79
80 static void image_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
81                                gint x, gint y,
82                                GtkSelectionData *selection_data, guint info,
83                                guint time, gpointer data)
84 {
85         ImageWindow *imd = data;
86
87         if (info == TARGET_URI_LIST)
88                 {
89                 GList *list = get_uri_file_list(selection_data->data);
90                 if (list)
91                         {
92                         gchar *path;
93
94                         path = list->data;
95
96                         if (imd == normal_image)
97                                 {
98                                 if (isfile(path))
99                                         {
100                                         gint row;
101                                         gchar *dir = remove_level_from_path(path);
102                                         if (strcmp(dir, current_path) != 0)
103                                                 filelist_change_to(dir);
104                                         g_free(dir);
105         
106                                         row = find_file_in_list(path);
107                                         if (row == -1)
108                                                 image_change_to(path);
109                                         else
110                                                 file_image_change_to(row);
111                                         }
112                                 else if (isdir(path))
113                                         {
114                                         filelist_change_to(path);
115                                         image_change_to(NULL);
116                                         }
117                                 }
118                         else
119                                 {
120                                 if (isfile(path))
121                                         {
122                                         image_area_set_image(imd, path, get_default_zoom(imd));
123                                         }
124                                 }
125
126                         if (debug)
127                                 {
128                                 GList *work = list;
129                                 while (work)
130                                         {
131                                         printf("dropped: %s\n", (gchar *)(work->data));
132                                         work = work->next;
133                                         }
134                                 }
135
136                         g_list_foreach(list, (GFunc)g_free, NULL);
137                         g_list_free(list);
138                         }
139                 }
140 }
141
142 static void image_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
143                                GtkSelectionData *selection_data, guint info,
144                                guint time, gpointer data)
145 {
146         ImageWindow *imd = data;
147         gchar *path = image_area_get_path(imd);
148
149         if (path)
150                 {
151                 gchar *text = NULL;
152                 switch (info)
153                         {
154                         case TARGET_URI_LIST:
155                                 text = g_strconcat("file:", path, "\r\n", NULL);
156                                 break;
157                         case TARGET_TEXT_PLAIN:
158                                 text = g_strdup(path);
159                                 break;
160                         }
161                 if (text)
162                         {
163                         gtk_selection_data_set (selection_data, selection_data->target,
164                                                 8, text, strlen(text));
165                         g_free(text);
166                         }
167                 }
168         else
169                 {
170                 gtk_selection_data_set (selection_data, selection_data->target,
171                                         8, NULL, 0);
172                 }
173 }
174
175 static void image_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
176 {
177         ImageWindow *imd = data;
178         if (context->action == GDK_ACTION_MOVE)
179                 {
180                 gint row = find_file_in_list(image_area_get_path(imd));
181                 if (row < 0) return;
182                 if (image_get_path() && strcmp(image_get_path(), image_area_get_path(imd)) == 0)
183                         {
184                         if (row < file_count() - 1)
185                                 {
186                                 file_next_image();
187                                 }
188                         else
189                                 {
190                                 file_prev_image();
191                                 }
192                         }
193                 filelist_refresh();
194                 }
195 }
196
197 void image_dnd_init(ImageWindow *imd)
198 {
199         gtk_drag_source_set(imd->viewport, GDK_BUTTON2_MASK,
200                                 file_drag_types, n_file_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
201         gtk_signal_connect(GTK_OBJECT(imd->viewport), "drag_data_get",
202                                 image_set_dnd_data, imd);
203         gtk_signal_connect(GTK_OBJECT(imd->viewport), "drag_end",
204                                 image_drag_end, imd);
205
206         gtk_drag_dest_set(imd->viewport,
207                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
208                           file_drop_types, n_file_drop_types,
209                           GDK_ACTION_COPY);
210         gtk_signal_connect(GTK_OBJECT(imd->viewport), "drag_data_received",
211                                 image_get_dnd_data, imd);
212 }
213
214 /*
215  *-----------------------------------------------------------------------------
216  * file list drag and drop routines (private)
217  *-----------------------------------------------------------------------------
218  */ 
219
220 static void file_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
221                               GtkSelectionData *selection_data, guint info,
222                               guint time, gpointer data)
223 {
224         gchar *uri_text = NULL;
225         gchar *leader = "file:";
226         gchar *sep = "\r\n";
227         gint total;
228         gint leader_l;
229         gint sep_l = strlen(sep);
230         gchar *ptr;
231
232         switch (info)
233                 {
234                 case TARGET_URI_LIST:
235                         leader_l = strlen(leader);
236                         break;
237                 case TARGET_TEXT_PLAIN:
238                         leader_l = 0;
239                         break;
240                 default:
241                         return;
242                         break;
243                 }
244         
245         if (file_clicked_is_selected())
246                 {
247                 GList *list;
248                 GList *work;
249
250                 list = file_get_selected_list();
251                 if (!list) return;
252                 work = list;
253                 total = 0;
254
255                 /* compute length */
256
257                 while (work)
258                         {
259                         gchar *name = work->data;
260                         total += leader_l + strlen(name) + sep_l;
261                         work = work->next;
262                         }
263
264                 /* create list */
265                 uri_text = g_malloc(total + 1);
266                 ptr = uri_text;
267
268                 work = list;
269                 while (work)
270                         {
271                         gchar *name = work->data;
272                         if (leader_l > 0)
273                                 {
274                                 strcpy(ptr, leader);
275                                 ptr += leader_l;
276                                 }
277                         strcpy(ptr, name);
278                         ptr += strlen(name);
279                         strcpy(ptr, sep);
280                         ptr += sep_l;
281                         work = work->next;
282                         }
283                 ptr[0] = '\0';
284                 free_selected_list(list);
285                 }
286         else
287                 {
288                 gchar *path = file_clicked_get_path();
289                 if (!path) return;
290                 switch (info)
291                         {
292                         case TARGET_URI_LIST:
293                                 uri_text = g_strconcat("file:", path, "\r\n", NULL);
294                                 break;
295                         case TARGET_TEXT_PLAIN:
296                                 uri_text = g_strdup(path);
297                                 break;
298                         }
299                 total = strlen(uri_text);
300                 g_free(path);
301                 }
302
303         if (debug) printf(uri_text);
304
305         gtk_selection_data_set (selection_data, selection_data->target,
306                                         8, uri_text, total);
307         g_free(uri_text);
308
309         file_clist_highlight_unset();
310 }
311
312 static void file_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
313 {
314         file_clist_highlight_set();
315 }
316
317 static void file_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
318 {
319         file_clist_highlight_unset();
320
321         if (context->action == GDK_ACTION_MOVE)
322                 {
323                 filelist_refresh();
324                 }
325 }
326
327 /*
328  *-----------------------------------------------------------------------------
329  * directory list drag and drop routines (private)
330  *-----------------------------------------------------------------------------
331  */ 
332
333 static void dir_list_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
334                               GtkSelectionData *selection_data, guint info,
335                               guint time, gpointer data)
336 {
337         gint row = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(dir_clist)));
338
339         if (row >= 0)
340                 {
341                 gchar *name = gtk_clist_get_row_data(GTK_CLIST(dir_clist), row);
342                 gchar *new_path;
343                 gchar *text = NULL;
344
345                 if (strcmp(name, ".") == 0)
346                         new_path = g_strdup(current_path);
347                 else if (strcmp(name, "..") == 0)
348                         new_path = remove_level_from_path(current_path);
349                 else
350                         {
351                         if (strcmp(current_path, "/") == 0)
352                                 new_path = g_strconcat(current_path, name, NULL);
353                         else
354                                 new_path = g_strconcat(current_path, "/", name, NULL);
355                         }
356
357                 
358                 switch (info)
359                         {
360                         case TARGET_URI_LIST:
361                                 text = g_strconcat("file:", new_path, "\r\n", NULL);
362                                 break;
363                         case TARGET_TEXT_PLAIN:
364                                 text = g_strdup(new_path);
365                                 break;
366                         }
367                 if (text)
368                         {
369                         gtk_selection_data_set (selection_data, selection_data->target,
370                                         8, text, strlen(text));
371                         g_free(text);
372                         }
373                 g_free(new_path);
374                 }
375 }
376
377 static void dir_clist_set_highlight(gint set)
378 {
379         gint row = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(dir_clist)));
380         if (set)
381                 {
382                 gtk_clist_set_background(GTK_CLIST(dir_clist), row,
383                         &GTK_WIDGET (dir_clist)->style->bg[GTK_STATE_SELECTED]);
384                 gtk_clist_set_foreground(GTK_CLIST(dir_clist), row,
385                         &GTK_WIDGET (dir_clist)->style->fg[GTK_STATE_SELECTED]);
386                 }
387         else
388                 {
389                 gtk_clist_set_background(GTK_CLIST(dir_clist), row, NULL);
390                 gtk_clist_set_foreground(GTK_CLIST(dir_clist), row, NULL);
391                 }
392 }
393
394 static void dir_list_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
395 {
396         dir_clist_set_highlight(TRUE);
397 }
398
399 static void dir_list_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
400 {
401         dir_clist_set_highlight(FALSE);
402
403         if (context->action == GDK_ACTION_MOVE)
404                 {
405                 filelist_refresh();
406                 }
407 }
408
409 /*
410  *-----------------------------------------------------------------------------
411  * drag and drop initialization (public)
412  *-----------------------------------------------------------------------------
413  */ 
414
415 void init_dnd()
416 {
417         /* dir clist */
418         gtk_drag_source_set(dir_clist, GDK_BUTTON2_MASK,
419                                 file_drag_types, n_file_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
420         gtk_signal_connect(GTK_OBJECT(dir_clist), "drag_begin",
421                                 dir_list_drag_begin, NULL);
422         gtk_signal_connect(GTK_OBJECT(dir_clist), "drag_data_get",
423                                 dir_list_set_dnd_data, NULL);
424         gtk_signal_connect(GTK_OBJECT(dir_clist), "drag_end",
425                                 dir_list_drag_end, NULL);
426
427         /* file clist */
428         gtk_drag_source_set(file_clist, GDK_BUTTON2_MASK,
429                                 file_drag_types, n_file_drag_types, GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
430         gtk_signal_connect(GTK_OBJECT(file_clist), "drag_begin",
431                                 file_list_drag_begin, NULL);
432         gtk_signal_connect(GTK_OBJECT(file_clist), "drag_data_get",
433                                 file_list_set_dnd_data, NULL);
434         gtk_signal_connect(GTK_OBJECT(file_clist), "drag_end",
435                                 file_list_drag_end, NULL);
436
437         /* image */
438         image_dnd_init(main_image);
439 }
440
441