diff options
Diffstat (limited to 'src/fs/gnunet-fs-gtk-event_handler.c')
-rw-r--r-- | src/fs/gnunet-fs-gtk-event_handler.c | 1053 |
1 files changed, 476 insertions, 577 deletions
diff --git a/src/fs/gnunet-fs-gtk-event_handler.c b/src/fs/gnunet-fs-gtk-event_handler.c index 8320c8bf..d9b4dab8 100644 --- a/src/fs/gnunet-fs-gtk-event_handler.c +++ b/src/fs/gnunet-fs-gtk-event_handler.c | |||
@@ -28,12 +28,11 @@ | |||
28 | #include "gnunet-fs-gtk-event_handler.h" | 28 | #include "gnunet-fs-gtk-event_handler.h" |
29 | #include <string.h> | 29 | #include <string.h> |
30 | 30 | ||
31 | static struct SearchTab *search_tab_head; | ||
32 | |||
33 | static struct SearchTab *search_tab_tail; | ||
34 | |||
35 | static struct SearchTab *uri_tab; | ||
36 | 31 | ||
32 | /** | ||
33 | * We have a single tab where we display publishing operations. | ||
34 | * So there is only one instance of this struct. | ||
35 | */ | ||
37 | struct PublishTab | 36 | struct PublishTab |
38 | { | 37 | { |
39 | 38 | ||
@@ -54,6 +53,11 @@ struct PublishTab | |||
54 | }; | 53 | }; |
55 | 54 | ||
56 | 55 | ||
56 | /** | ||
57 | * Information we keep for each file or directory being published. | ||
58 | * Used to quickly identify the tab and row of the operation; stored | ||
59 | * in the user-context of the FS library for the publish operation. | ||
60 | */ | ||
57 | struct PublishEntry | 61 | struct PublishEntry |
58 | { | 62 | { |
59 | /** | 63 | /** |
@@ -76,10 +80,19 @@ struct PublishEntry | |||
76 | */ | 80 | */ |
77 | struct GNUNET_FS_Uri *uri; | 81 | struct GNUNET_FS_Uri *uri; |
78 | 82 | ||
83 | /** | ||
84 | * Is this the top-level entry for the publish operation | ||
85 | * or sub-operation? | ||
86 | */ | ||
79 | int is_top; | 87 | int is_top; |
80 | }; | 88 | }; |
81 | 89 | ||
82 | 90 | ||
91 | /** | ||
92 | * Information we keep for each search result. Used to quickly | ||
93 | * identify the tab and row of the result; stored in the user-context | ||
94 | * of the FS library for the search result. | ||
95 | */ | ||
83 | struct SearchResult | 96 | struct SearchResult |
84 | { | 97 | { |
85 | /** | 98 | /** |
@@ -105,48 +118,450 @@ struct SearchResult | |||
105 | }; | 118 | }; |
106 | 119 | ||
107 | 120 | ||
108 | struct StartDownloadContext | ||
109 | { | ||
110 | struct SearchTab *tab; | ||
111 | gboolean recursive; | ||
112 | }; | ||
113 | 121 | ||
122 | /** | ||
123 | * Head of linked list of tabs for searches. | ||
124 | */ | ||
125 | static struct SearchTab *search_tab_head; | ||
126 | |||
127 | /** | ||
128 | * Tail of linked list of tabs for searches. | ||
129 | */ | ||
130 | static struct SearchTab *search_tab_tail; | ||
131 | |||
132 | /** | ||
133 | * Special tab we use to for downloads-by-URIs and downloads | ||
134 | * where the search tab has been closed ("parent lost"). | ||
135 | */ | ||
136 | static struct SearchTab *uri_tab; | ||
137 | |||
138 | /** | ||
139 | * Special tab we use to store publishing operations. | ||
140 | */ | ||
114 | static struct PublishTab *publish_tab; | 141 | static struct PublishTab *publish_tab; |
115 | 142 | ||
116 | /** | 143 | /** |
117 | * Row reference for the current search context menu. | 144 | * Row reference for the current search context menu. |
145 | * FIXME: de-globalize? | ||
118 | */ | 146 | */ |
119 | static GtkTreeRowReference *current_context_row_reference; | 147 | static GtkTreeRowReference *current_context_row_reference; |
120 | 148 | ||
121 | /** | 149 | /** |
122 | * Search tab used for the current search context menu. | 150 | * Search tab used for the current search context menu. |
151 | * FIXME: de-globalize? | ||
123 | */ | 152 | */ |
124 | static struct SearchTab *current_context_search_tab; | 153 | static struct SearchTab *current_context_search_tab; |
125 | 154 | ||
126 | static void | ||
127 | start_download_ctx_menu (GtkMenuItem *item, gpointer user_data); | ||
128 | 155 | ||
156 | |||
157 | /** | ||
158 | * Closure for the 'start_download' callback. | ||
159 | */ | ||
160 | struct StartDownloadContext | ||
161 | { | ||
162 | /** | ||
163 | * Search tab to search for the request. | ||
164 | */ | ||
165 | struct SearchTab *tab; | ||
166 | |||
167 | /** | ||
168 | * Was the 'recursive' option requested? | ||
169 | */ | ||
170 | gboolean recursive; | ||
171 | |||
172 | }; | ||
173 | |||
174 | |||
175 | /** | ||
176 | * This should get the default download directory (so that GNUnet | ||
177 | * won't offer the user to download files to the 'bin' subdirectory, | ||
178 | * or whatever is the cwd). Returns NULL on failure (such as | ||
179 | * non-existend directory). Should also preserve the last setting (so | ||
180 | * if the user saves files somewhere else, next time we default to | ||
181 | * somewhere else, at least until application restart, or maybe even | ||
182 | * between application restarts). | ||
183 | * | ||
184 | * Fills the @buffer up to @size bytes, returns a pointer to it. | ||
185 | */ | ||
186 | static char * | ||
187 | get_default_download_directory (char *buffer, size_t size) | ||
188 | { | ||
189 | return NULL; | ||
190 | } | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Called recursively to build a suggested filename by prepending | ||
195 | * suggested names for its parent directories (if any). | ||
196 | * | ||
197 | * @param tm FIXME | ||
198 | * @param iter FIXME | ||
199 | * @param top FIXME | ||
200 | * @param local_parents set to GNUNET_YES if all parents are directories, and are downloaded. | ||
201 | * @param anonymity FIXME | ||
202 | * @param filename_is_absolute FIXME | ||
203 | * @return suggested filename, possibly NULL | ||
204 | */ | ||
205 | static char * | ||
206 | get_suggested_filename_anonymity (GtkTreeModel *tm, | ||
207 | GtkTreeIter *iter, | ||
208 | int top, | ||
209 | int *local_parents, | ||
210 | int *anonymity, | ||
211 | int *filename_is_absolute) | ||
212 | { | ||
213 | char *result; | ||
214 | char *dirname; | ||
215 | char *local_filename, *filename; | ||
216 | int downloaded_anonymity; | ||
217 | int have_a_parent; | ||
218 | struct GNUNET_CONTAINER_MetaData *meta; | ||
219 | GtkTreeIter parent; | ||
220 | gtk_tree_model_get (tm, iter, 0, &meta, 15, &local_filename, 16, &downloaded_anonymity, -1); | ||
221 | if (local_filename == NULL && !top) | ||
222 | *local_parents = GNUNET_NO; | ||
223 | if (downloaded_anonymity != -1 && *anonymity == -1 && !top) | ||
224 | *anonymity = downloaded_anonymity; | ||
225 | if (gtk_tree_model_iter_parent (tm, &parent, iter)) | ||
226 | { | ||
227 | have_a_parent = GNUNET_YES; | ||
228 | dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO, local_parents, anonymity, filename_is_absolute); | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | have_a_parent = GNUNET_NO; | ||
233 | dirname = NULL; | ||
234 | if (top) | ||
235 | *local_parents = GNUNET_NO; | ||
236 | } | ||
237 | if (local_filename == NULL) | ||
238 | filename = GNUNET_FS_meta_data_suggest_filename (meta); | ||
239 | else | ||
240 | { | ||
241 | /* This directory was downloaded as /foo/bar/baz/somedirname | ||
242 | * Hopefully, "somedirname" is actually "somedir.gnd" | ||
243 | * We need to strip the ".gnd" part to get "somedir", which is | ||
244 | * what we're going to use instead of suggested original filename | ||
245 | * Without the .gnd extension we're going to just use a copy | ||
246 | * of the directory file name - and that would fail. Sad. | ||
247 | */ | ||
248 | const char *basename; | ||
249 | if (dirname == NULL && !have_a_parent) | ||
250 | { | ||
251 | /* This is the ealderlest parent directory. Use absolute path. */ | ||
252 | basename = (const char *) local_filename; | ||
253 | *filename_is_absolute = GNUNET_YES; | ||
254 | } | ||
255 | else | ||
256 | basename = GNUNET_STRINGS_get_short_name (local_filename); | ||
257 | if (basename != NULL && strlen (basename) > 0) | ||
258 | { | ||
259 | char *dot; | ||
260 | filename = GNUNET_strdup (basename); | ||
261 | dot = strrchr (filename, '.'); | ||
262 | if (dot) | ||
263 | *dot = '\0'; | ||
264 | } | ||
265 | else | ||
266 | filename = GNUNET_FS_meta_data_suggest_filename (meta); | ||
267 | } | ||
268 | if (dirname && filename) | ||
269 | { | ||
270 | GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename); | ||
271 | GNUNET_free (filename); | ||
272 | GNUNET_free (dirname); | ||
273 | return result; | ||
274 | } | ||
275 | else if (filename) | ||
276 | return filename; | ||
277 | else | ||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * This function is called when the user double-clicks on a search | ||
284 | * result. Begins the download, if necessary by opening the "save as" | ||
285 | * window. | ||
286 | * | ||
287 | * @param tree_view tree view with the details | ||
288 | * @param path path selecting which entry we want to download | ||
289 | * @param column unused entry specifying which column the mouse was in | ||
290 | * @param user_data a 'struct StartDownloadContext' with additional details | ||
291 | */ | ||
129 | static void | 292 | static void |
130 | start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data); | 293 | start_download (GtkTreeView * tree_view, GtkTreePath * path, |
294 | GtkTreeViewColumn * column, gpointer user_data) | ||
295 | { | ||
296 | struct StartDownloadContext *sdc = user_data; | ||
297 | struct SearchTab *tab = sdc->tab; | ||
298 | GtkTreeModel *tm; | ||
299 | GtkTreeIter iter; | ||
300 | struct GNUNET_FS_Uri *uri; | ||
301 | struct GNUNET_CONTAINER_MetaData *meta; | ||
302 | struct SearchResult *sr; | ||
303 | gchar *mime; | ||
304 | struct DownloadContext *dc; | ||
305 | char *buf = NULL; | ||
306 | char *tmp; | ||
307 | size_t tmplen; | ||
308 | char cwd[FILENAME_MAX]; | ||
309 | char *download_directory; | ||
310 | char *filename; | ||
311 | int local_parents; | ||
312 | int have_a_suggestion; | ||
313 | int anonymity; | ||
314 | int filename_is_absolute; | ||
315 | |||
316 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
317 | "Starting a %sdownload\n", | ||
318 | sdc->recursive ? "recursive " : ""); | ||
319 | |||
320 | GNUNET_assert (tab != NULL); | ||
321 | tm = gtk_tree_view_get_model (tree_view); | ||
322 | if (TRUE != gtk_tree_model_get_iter (tm, &iter, path)) | ||
323 | { | ||
324 | GNUNET_break (0); | ||
325 | // FIXME: this is bad... | ||
326 | GNUNET_free (sdc); | ||
327 | return; | ||
328 | } | ||
329 | gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, 9, &sr, 10, &mime, -1); | ||
330 | if (NULL == uri) | ||
331 | { | ||
332 | /* user clicked on directory that was opened (not downloaded!), so we | ||
333 | have no URI and downloading makes no sense. Ignore! */ | ||
334 | if (NULL != mime) | ||
335 | g_free (mime); | ||
336 | return; | ||
337 | } | ||
338 | if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri))) | ||
339 | { | ||
340 | /* can only download chk/loc URIs, ignore */ | ||
341 | g_free (mime); | ||
342 | return; | ||
343 | } | ||
131 | 344 | ||
345 | download_directory = get_default_download_directory (cwd, sizeof (cwd)); | ||
346 | /* If no download directory is known, try working directory */ | ||
347 | if (download_directory == NULL) | ||
348 | download_directory = getcwd (cwd, sizeof (cwd)); | ||
349 | /* Calculate suggested filename */ | ||
350 | local_parents = GNUNET_YES; | ||
351 | anonymity = -1; | ||
352 | filename_is_absolute = GNUNET_NO; | ||
353 | filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES, &local_parents, &anonymity, &filename_is_absolute); | ||
354 | have_a_suggestion = GNUNET_NO; | ||
355 | if (NULL != download_directory) | ||
356 | { | ||
357 | if (NULL == filename) | ||
358 | { | ||
359 | buf = GNUNET_strdup (download_directory); | ||
360 | } | ||
361 | else | ||
362 | { | ||
363 | have_a_suggestion = GNUNET_YES; | ||
364 | if (filename_is_absolute) | ||
365 | GNUNET_asprintf (&tmp, "%s", filename); | ||
366 | else | ||
367 | GNUNET_asprintf (&tmp, "%s%s%s", | ||
368 | download_directory, | ||
369 | DIR_SEPARATOR_STR, | ||
370 | filename); | ||
371 | tmplen = strlen (tmp); | ||
372 | /* now, if we have a directory, replace trailing '/' with ".gnd" */ | ||
373 | if (GNUNET_YES == | ||
374 | GNUNET_FS_meta_data_test_for_directory (meta)) | ||
375 | { | ||
376 | if ( (tmp[tmplen-1] == '/') || | ||
377 | (tmp[tmplen-1] == '\\') ) | ||
378 | tmp[tmplen-1] = '\0'; | ||
379 | GNUNET_asprintf (&buf, | ||
380 | "%s%s", | ||
381 | tmp, | ||
382 | GNUNET_FS_DIRECTORY_EXT); | ||
383 | GNUNET_free (tmp); | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | buf = tmp; | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | GNUNET_free_non_null (filename); | ||
392 | |||
393 | /* now setup everything for the save-as dialog */ | ||
394 | dc = GNUNET_malloc (sizeof (struct DownloadContext)); | ||
395 | dc->uri = GNUNET_FS_uri_dup (uri); | ||
396 | dc->mime = mime; | ||
397 | dc->filename = buf; | ||
398 | dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
399 | dc->rr = gtk_tree_row_reference_new (tm, path); | ||
400 | dc->sr = sr->result; | ||
401 | dc->anonymity = anonymity; | ||
402 | dc->is_recursive = sdc->recursive; | ||
403 | dc->tab = tab; | ||
404 | if (local_parents && have_a_suggestion) | ||
405 | /* Skip the dialog, call directly */ | ||
406 | GNUNET_FS_GTK_download_context_start_download (dc); | ||
407 | else | ||
408 | GNUNET_FS_GTK_open_download_as_dialog (dc); | ||
409 | } | ||
410 | |||
411 | |||
412 | /** | ||
413 | * An item was selected from the context menu; destroy | ||
414 | * the menu shell. | ||
415 | * | ||
416 | * @param menushell menu to destroy | ||
417 | * @parma user_data the 'struct DownloadEntry' for the menu (unused) | ||
418 | */ | ||
132 | static void | 419 | static void |
133 | abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data); | 420 | search_list_popup_selection_done (GtkMenuShell *menushell, |
421 | gpointer user_data) | ||
422 | { | ||
423 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
424 | "Item selected in menu shell %p, destroying it.\n", | ||
425 | menushell); | ||
426 | gtk_widget_destroy (GTK_WIDGET (menushell)); | ||
427 | } | ||
134 | 428 | ||
429 | |||
430 | /** | ||
431 | * "Download" was selected in the current search context menu. | ||
432 | * | ||
433 | * @param item the 'download' menu item | ||
434 | * @parma user_data the 'struct DownloadEntry' to download. | ||
435 | */ | ||
135 | static void | 436 | static void |
136 | copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data); | 437 | start_download_ctx_menu (GtkMenuItem *item, gpointer user_data) |
438 | { | ||
439 | GtkTreePath *path; | ||
440 | GtkTreeView *tv; | ||
441 | struct StartDownloadContext sdc; | ||
442 | |||
443 | if (current_context_row_reference == NULL) | ||
444 | { | ||
445 | GNUNET_break (0); | ||
446 | return; | ||
447 | } | ||
448 | path = gtk_tree_row_reference_get_path (current_context_row_reference); | ||
449 | gtk_tree_row_reference_free (current_context_row_reference); | ||
450 | current_context_row_reference = NULL; | ||
451 | tv = GTK_TREE_VIEW (gtk_builder_get_object | ||
452 | (current_context_search_tab->builder, | ||
453 | "_search_result_frame")); | ||
454 | sdc.tab = current_context_search_tab; | ||
455 | sdc.recursive = FALSE; | ||
456 | start_download (tv, path, NULL, &sdc); | ||
457 | gtk_tree_path_free (path); | ||
458 | current_context_search_tab = NULL; | ||
459 | } | ||
460 | |||
137 | 461 | ||
462 | /** | ||
463 | * "Download recursively" was selected in the current search context menu. | ||
464 | * | ||
465 | * @param item the 'download recursively' menu item | ||
466 | * @parma user_data the 'struct DownloadEntry' to download. | ||
467 | */ | ||
138 | static void | 468 | static void |
139 | free_search_result (struct SearchResult *sr); | 469 | start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data) |
470 | { | ||
471 | GtkTreePath *path; | ||
472 | GtkTreeView *tv; | ||
473 | struct StartDownloadContext sdc; | ||
140 | 474 | ||
141 | void | 475 | if (current_context_row_reference == NULL) |
142 | search_list_popup_selection_done (GtkMenuShell *menushell, | 476 | { |
143 | gpointer user_data) | 477 | GNUNET_break (0); |
478 | return; | ||
479 | } | ||
480 | path = gtk_tree_row_reference_get_path (current_context_row_reference); | ||
481 | gtk_tree_row_reference_free (current_context_row_reference); | ||
482 | current_context_row_reference = NULL; | ||
483 | tv = GTK_TREE_VIEW (gtk_builder_get_object | ||
484 | (current_context_search_tab->builder, | ||
485 | "_search_result_frame")); | ||
486 | sdc.tab = current_context_search_tab; | ||
487 | sdc.recursive = TRUE; | ||
488 | start_download (tv, path, NULL, &sdc); | ||
489 | gtk_tree_path_free (path); | ||
490 | current_context_search_tab = NULL; | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Download "abort" was selected in the current search context menu. | ||
496 | * | ||
497 | * @param item the 'abort' menu item | ||
498 | * @parma user_data the 'struct DownloadEntry' to abort. | ||
499 | */ | ||
500 | static void | ||
501 | abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data) | ||
144 | { | 502 | { |
503 | struct DownloadEntry *de = user_data; | ||
504 | |||
145 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 505 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
146 | "Item selected in menu shell %x\n", menushell); | 506 | "Aborting download DE=%p\n", |
147 | gtk_widget_destroy (GTK_WIDGET (menushell)); | 507 | de); |
508 | GNUNET_assert (de->dc != NULL); | ||
509 | GNUNET_FS_download_stop (de->dc, GNUNET_YES); | ||
510 | current_context_search_tab = NULL; | ||
148 | } | 511 | } |
149 | 512 | ||
513 | |||
514 | /** | ||
515 | * Copy current URI to clipboard. | ||
516 | * | ||
517 | * @param item the 'copy-to-clipboard' menu item | ||
518 | * @parma user_data the 'struct DownloadEntry' to copy from | ||
519 | */ | ||
520 | static void | ||
521 | copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data) | ||
522 | { | ||
523 | GtkTreePath *path; | ||
524 | GtkTreeView *tv; | ||
525 | GtkTreeModel *tm; | ||
526 | GtkTreeIter iter; | ||
527 | struct GNUNET_FS_Uri *uri; | ||
528 | char *uris; | ||
529 | GtkClipboard *cb; | ||
530 | |||
531 | if (current_context_row_reference == NULL) | ||
532 | { | ||
533 | GNUNET_break (0); | ||
534 | return; | ||
535 | } | ||
536 | path = gtk_tree_row_reference_get_path (current_context_row_reference); | ||
537 | gtk_tree_row_reference_free (current_context_row_reference); | ||
538 | current_context_row_reference = NULL; | ||
539 | tv = GTK_TREE_VIEW (gtk_builder_get_object | ||
540 | (current_context_search_tab->builder, | ||
541 | "_search_result_frame")); | ||
542 | tm = gtk_tree_view_get_model (tv); | ||
543 | if (TRUE != gtk_tree_model_get_iter (tm, &iter, path)) | ||
544 | { | ||
545 | GNUNET_break (0); | ||
546 | gtk_tree_path_free (path); | ||
547 | return; | ||
548 | } | ||
549 | gtk_tree_model_get (tm, &iter, 1, &uri, -1); | ||
550 | gtk_tree_path_free (path); | ||
551 | current_context_search_tab = NULL; | ||
552 | if (uri == NULL) | ||
553 | { | ||
554 | GNUNET_break (0); | ||
555 | return; | ||
556 | } | ||
557 | uris = GNUNET_FS_uri_to_string (uri); | ||
558 | cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); | ||
559 | gtk_clipboard_set_text (cb, uris, -1); | ||
560 | gtk_clipboard_store (cb); | ||
561 | GNUNET_free (uris); | ||
562 | } | ||
563 | |||
564 | |||
150 | static gboolean | 565 | static gboolean |
151 | search_list_popup (GtkTreeView *tv, struct SearchTab *tab, GdkEventButton *event_button) | 566 | search_list_popup (GtkTreeView *tv, struct SearchTab *tab, GdkEventButton *event_button) |
152 | { | 567 | { |
@@ -813,345 +1228,9 @@ setup_download (struct DownloadEntry *de, struct DownloadEntry *pde, | |||
813 | return de; | 1228 | return de; |
814 | } | 1229 | } |
815 | 1230 | ||
816 | /** | ||
817 | * This should get the default download directory | ||
818 | * (so that GNUnet won't offer the user to download files | ||
819 | * to the 'bin' subdirectory, or whatever is the cwd). | ||
820 | * Returns NULL on failure (such as non-existend directory). | ||
821 | * Should also preserve the last setting (so if the user | ||
822 | * saves files somewhere else, next time we default to | ||
823 | * somewhere else, at least until application restart, or maybe even | ||
824 | * between application restarts). | ||
825 | * Fills the @buffer up to @size bytes, returns a pointer to it. | ||
826 | */ | ||
827 | static char * | ||
828 | get_default_download_directory (char *buffer, size_t size) | ||
829 | { | ||
830 | return NULL; | ||
831 | } | ||
832 | |||
833 | /** | ||
834 | * Called recursively to build a suggested filename by | ||
835 | * prepending suggested names for its parent directories (if any). | ||
836 | * Might return NULL. Returned name might be absolute. | ||
837 | * local_parents is set to GNUNET_YES if all parents are directories, | ||
838 | * and are downloaded. | ||
839 | */ | ||
840 | static char * | ||
841 | get_suggested_filename_anonymity (GtkTreeModel *tm, GtkTreeIter *iter, int top, | ||
842 | int *local_parents, int *anonymity, int *filename_is_absolute) | ||
843 | { | ||
844 | char *result; | ||
845 | char *dirname; | ||
846 | char *local_filename, *filename; | ||
847 | int downloaded_anonymity; | ||
848 | int have_a_parent; | ||
849 | struct GNUNET_CONTAINER_MetaData *meta; | ||
850 | GtkTreeIter parent; | ||
851 | gtk_tree_model_get (tm, iter, 0, &meta, 15, &local_filename, 16, &downloaded_anonymity, -1); | ||
852 | if (local_filename == NULL && !top) | ||
853 | *local_parents = GNUNET_NO; | ||
854 | if (downloaded_anonymity != -1 && *anonymity == -1 && !top) | ||
855 | *anonymity = downloaded_anonymity; | ||
856 | if (gtk_tree_model_iter_parent (tm, &parent, iter)) | ||
857 | { | ||
858 | have_a_parent = GNUNET_YES; | ||
859 | dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO, local_parents, anonymity, filename_is_absolute); | ||
860 | } | ||
861 | else | ||
862 | { | ||
863 | have_a_parent = GNUNET_NO; | ||
864 | dirname = NULL; | ||
865 | if (top) | ||
866 | *local_parents = GNUNET_NO; | ||
867 | } | ||
868 | if (local_filename == NULL) | ||
869 | filename = GNUNET_FS_meta_data_suggest_filename (meta); | ||
870 | else | ||
871 | { | ||
872 | /* This directory was downloaded as /foo/bar/baz/somedirname | ||
873 | * Hopefully, "somedirname" is actually "somedir.gnd" | ||
874 | * We need to strip the ".gnd" part to get "somedir", which is | ||
875 | * what we're going to use instead of suggested original filename | ||
876 | * Without the .gnd extension we're going to just use a copy | ||
877 | * of the directory file name - and that would fail. Sad. | ||
878 | */ | ||
879 | const char *basename; | ||
880 | if (dirname == NULL && !have_a_parent) | ||
881 | { | ||
882 | /* This is the ealderlest parent directory. Use absolute path. */ | ||
883 | basename = (const char *) local_filename; | ||
884 | *filename_is_absolute = GNUNET_YES; | ||
885 | } | ||
886 | else | ||
887 | basename = GNUNET_STRINGS_get_short_name (local_filename); | ||
888 | if (basename != NULL && strlen (basename) > 0) | ||
889 | { | ||
890 | char *dot; | ||
891 | filename = GNUNET_strdup (basename); | ||
892 | dot = strrchr (filename, '.'); | ||
893 | if (dot) | ||
894 | *dot = '\0'; | ||
895 | } | ||
896 | else | ||
897 | filename = GNUNET_FS_meta_data_suggest_filename (meta); | ||
898 | } | ||
899 | if (dirname && filename) | ||
900 | { | ||
901 | GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename); | ||
902 | GNUNET_free (filename); | ||
903 | GNUNET_free (dirname); | ||
904 | return result; | ||
905 | } | ||
906 | else if (filename) | ||
907 | return filename; | ||
908 | else | ||
909 | return NULL; | ||
910 | } | ||
911 | |||
912 | /** | ||
913 | * Tell FS to start a download. Begins by opening the | ||
914 | * "save as" window. | ||
915 | */ | ||
916 | static void | ||
917 | start_download (GtkTreeView * tree_view, GtkTreePath * path, | ||
918 | GtkTreeViewColumn * column, gpointer user_data) | ||
919 | { | ||
920 | struct StartDownloadContext *sdc = user_data; | ||
921 | struct SearchTab *tab = sdc->tab; | ||
922 | GtkTreeModel *tm; | ||
923 | GtkTreeIter iter; | ||
924 | struct GNUNET_FS_Uri *uri; | ||
925 | struct GNUNET_CONTAINER_MetaData *meta; | ||
926 | struct SearchResult *sr; | ||
927 | gchar *mime; | ||
928 | struct DownloadContext *dc; | ||
929 | char *buf = NULL; | ||
930 | char *tmp; | ||
931 | size_t tmplen; | ||
932 | char cwd[FILENAME_MAX]; | ||
933 | char *download_directory; | ||
934 | char *filename; | ||
935 | int local_parents; | ||
936 | int have_a_suggestion; | ||
937 | int anonymity; | ||
938 | int filename_is_absolute; | ||
939 | |||
940 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
941 | "Starting a %sdownload\n", sdc->recursive ? "recursive " : ""); | ||
942 | |||
943 | GNUNET_assert (tab != NULL); | ||
944 | tm = gtk_tree_view_get_model (tree_view); | ||
945 | if (TRUE != gtk_tree_model_get_iter (tm, &iter, path)) | ||
946 | { | ||
947 | GNUNET_break (0); | ||
948 | GNUNET_free (sdc); | ||
949 | return; | ||
950 | } | ||
951 | gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, 9, &sr, 10, &mime, -1); | ||
952 | if (NULL == uri) | ||
953 | { | ||
954 | /* user clicked on directory that was opened (not downloaded!), so we | ||
955 | have no URI and downloading makes no sense. Ignore! */ | ||
956 | if (NULL != mime) | ||
957 | g_free (mime); | ||
958 | return; | ||
959 | } | ||
960 | if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri))) | ||
961 | { | ||
962 | /* can only download chk/loc URIs, ignore */ | ||
963 | g_free (mime); | ||
964 | return; | ||
965 | } | ||
966 | |||
967 | download_directory = get_default_download_directory (cwd, sizeof (cwd)); | ||
968 | /* If no download directory is known, try working directory */ | ||
969 | if (download_directory == NULL) | ||
970 | download_directory = getcwd (cwd, sizeof (cwd)); | ||
971 | /* Calculate suggested filename */ | ||
972 | local_parents = GNUNET_YES; | ||
973 | anonymity = -1; | ||
974 | filename_is_absolute = GNUNET_NO; | ||
975 | filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES, &local_parents, &anonymity, &filename_is_absolute); | ||
976 | have_a_suggestion = GNUNET_NO; | ||
977 | if (NULL != download_directory) | ||
978 | { | ||
979 | if (NULL == filename) | ||
980 | { | ||
981 | buf = GNUNET_strdup (download_directory); | ||
982 | } | ||
983 | else | ||
984 | { | ||
985 | have_a_suggestion = GNUNET_YES; | ||
986 | if (filename_is_absolute) | ||
987 | GNUNET_asprintf (&tmp, "%s", filename); | ||
988 | else | ||
989 | GNUNET_asprintf (&tmp, "%s%s%s", | ||
990 | download_directory, | ||
991 | DIR_SEPARATOR_STR, | ||
992 | filename); | ||
993 | tmplen = strlen (tmp); | ||
994 | /* now, if we have a directory, replace trailing '/' with ".gnd" */ | ||
995 | if (GNUNET_YES == | ||
996 | GNUNET_FS_meta_data_test_for_directory (meta)) | ||
997 | { | ||
998 | if ( (tmp[tmplen-1] == '/') || | ||
999 | (tmp[tmplen-1] == '\\') ) | ||
1000 | tmp[tmplen-1] = '\0'; | ||
1001 | GNUNET_asprintf (&buf, | ||
1002 | "%s%s", | ||
1003 | tmp, | ||
1004 | GNUNET_FS_DIRECTORY_EXT); | ||
1005 | GNUNET_free (tmp); | ||
1006 | } | ||
1007 | else | ||
1008 | { | ||
1009 | buf = tmp; | ||
1010 | } | ||
1011 | } | ||
1012 | } | ||
1013 | GNUNET_free_non_null (filename); | ||
1014 | |||
1015 | /* now setup everything for the save-as dialog */ | ||
1016 | dc = GNUNET_malloc (sizeof (struct DownloadContext)); | ||
1017 | dc->uri = GNUNET_FS_uri_dup (uri); | ||
1018 | dc->mime = mime; | ||
1019 | dc->filename = buf; | ||
1020 | dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); | ||
1021 | dc->rr = gtk_tree_row_reference_new (tm, path); | ||
1022 | dc->sr = sr->result; | ||
1023 | dc->anonymity = anonymity; | ||
1024 | dc->is_recursive = sdc->recursive; | ||
1025 | dc->tab = tab; | ||
1026 | if (local_parents && have_a_suggestion) | ||
1027 | /* Skip the dialog, call directly */ | ||
1028 | GNUNET_FS_GTK_download_context_start_download (dc); | ||
1029 | else | ||
1030 | GNUNET_FS_GTK_open_download_as_dialog (dc); | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | |||
1035 | /** | ||
1036 | * "Download" was selected in the current search context menu. | ||
1037 | */ | ||
1038 | static void | ||
1039 | start_download_ctx_menu (GtkMenuItem *item, gpointer user_data) | ||
1040 | { | ||
1041 | GtkTreePath *path; | ||
1042 | GtkTreeView *tv; | ||
1043 | struct StartDownloadContext sdc; | ||
1044 | |||
1045 | if (current_context_row_reference == NULL) | ||
1046 | { | ||
1047 | GNUNET_break (0); | ||
1048 | return; | ||
1049 | } | ||
1050 | path = gtk_tree_row_reference_get_path (current_context_row_reference); | ||
1051 | gtk_tree_row_reference_free (current_context_row_reference); | ||
1052 | current_context_row_reference = NULL; | ||
1053 | tv = GTK_TREE_VIEW (gtk_builder_get_object | ||
1054 | (current_context_search_tab->builder, | ||
1055 | "_search_result_frame")); | ||
1056 | sdc.tab = current_context_search_tab; | ||
1057 | sdc.recursive = FALSE; | ||
1058 | start_download (tv, path, NULL, &sdc); | ||
1059 | gtk_tree_path_free (path); | ||
1060 | current_context_search_tab = NULL; | ||
1061 | } | ||
1062 | |||
1063 | /** | ||
1064 | * "Download recursively" was selected in the current search context menu. | ||
1065 | */ | ||
1066 | static void | ||
1067 | start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data) | ||
1068 | { | ||
1069 | GtkTreePath *path; | ||
1070 | GtkTreeView *tv; | ||
1071 | struct StartDownloadContext sdc; | ||
1072 | |||
1073 | if (current_context_row_reference == NULL) | ||
1074 | { | ||
1075 | GNUNET_break (0); | ||
1076 | return; | ||
1077 | } | ||
1078 | path = gtk_tree_row_reference_get_path (current_context_row_reference); | ||
1079 | gtk_tree_row_reference_free (current_context_row_reference); | ||
1080 | current_context_row_reference = NULL; | ||
1081 | tv = GTK_TREE_VIEW (gtk_builder_get_object | ||
1082 | (current_context_search_tab->builder, | ||
1083 | "_search_result_frame")); | ||
1084 | sdc.tab = current_context_search_tab; | ||
1085 | sdc.recursive = TRUE; | ||
1086 | start_download (tv, path, NULL, &sdc); | ||
1087 | gtk_tree_path_free (path); | ||
1088 | current_context_search_tab = NULL; | ||
1089 | } | ||
1090 | 1231 | ||
1091 | 1232 | ||
1092 | /** | ||
1093 | * Download was selected in the current search context menu. | ||
1094 | */ | ||
1095 | static void | ||
1096 | abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data) | ||
1097 | { | ||
1098 | struct DownloadEntry *de = user_data; | ||
1099 | 1233 | ||
1100 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1101 | "Aborting a download DE=%p\n", de); | ||
1102 | |||
1103 | GNUNET_assert (de->dc != NULL); | ||
1104 | GNUNET_FS_download_stop (de->dc, GNUNET_YES); | ||
1105 | current_context_search_tab = NULL; | ||
1106 | } | ||
1107 | |||
1108 | |||
1109 | /** | ||
1110 | * Copy current URI to clipboard. | ||
1111 | */ | ||
1112 | static void | ||
1113 | copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data) | ||
1114 | { | ||
1115 | GtkTreePath *path; | ||
1116 | GtkTreeView *tv; | ||
1117 | GtkTreeModel *tm; | ||
1118 | GtkTreeIter iter; | ||
1119 | struct GNUNET_FS_Uri *uri; | ||
1120 | char *uris; | ||
1121 | GtkClipboard *cb; | ||
1122 | |||
1123 | if (current_context_row_reference == NULL) | ||
1124 | { | ||
1125 | GNUNET_break (0); | ||
1126 | return; | ||
1127 | } | ||
1128 | path = gtk_tree_row_reference_get_path (current_context_row_reference); | ||
1129 | gtk_tree_row_reference_free (current_context_row_reference); | ||
1130 | current_context_row_reference = NULL; | ||
1131 | tv = GTK_TREE_VIEW (gtk_builder_get_object | ||
1132 | (current_context_search_tab->builder, | ||
1133 | "_search_result_frame")); | ||
1134 | tm = gtk_tree_view_get_model (tv); | ||
1135 | if (TRUE != gtk_tree_model_get_iter (tm, &iter, path)) | ||
1136 | { | ||
1137 | GNUNET_break (0); | ||
1138 | gtk_tree_path_free (path); | ||
1139 | return; | ||
1140 | } | ||
1141 | gtk_tree_model_get (tm, &iter, 1, &uri, -1); | ||
1142 | gtk_tree_path_free (path); | ||
1143 | current_context_search_tab = NULL; | ||
1144 | if (uri == NULL) | ||
1145 | { | ||
1146 | GNUNET_break (0); | ||
1147 | return; | ||
1148 | } | ||
1149 | uris = GNUNET_FS_uri_to_string (uri); | ||
1150 | cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); | ||
1151 | gtk_clipboard_set_text (cb, uris, -1); | ||
1152 | gtk_clipboard_store (cb); | ||
1153 | GNUNET_free (uris); | ||
1154 | } | ||
1155 | 1234 | ||
1156 | gboolean | 1235 | gboolean |
1157 | search_list_on_popup (GtkWidget *widget, gpointer user_data) | 1236 | search_list_on_popup (GtkWidget *widget, gpointer user_data) |
@@ -1375,6 +1454,46 @@ stop_search (GtkButton * button, gpointer user_data) | |||
1375 | } | 1454 | } |
1376 | 1455 | ||
1377 | 1456 | ||
1457 | static void | ||
1458 | free_search_result (struct SearchResult *sr) | ||
1459 | { | ||
1460 | GtkTreePath *tp; | ||
1461 | GtkTreeModel *tm; | ||
1462 | GtkTreeIter iter; | ||
1463 | struct GNUNET_FS_Uri *uri; | ||
1464 | struct GNUNET_CONTAINER_MetaData *meta; | ||
1465 | |||
1466 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1467 | "Freeing a search result SR=%p\n", sr); | ||
1468 | |||
1469 | if (sr == NULL) | ||
1470 | { | ||
1471 | GNUNET_break (0); | ||
1472 | return; | ||
1473 | } | ||
1474 | GNUNET_assert (sr->rr != NULL); | ||
1475 | tp = gtk_tree_row_reference_get_path (sr->rr); | ||
1476 | GNUNET_assert (tp != NULL); | ||
1477 | tm = gtk_tree_row_reference_get_model (sr->rr); | ||
1478 | GNUNET_assert (tm != NULL); | ||
1479 | if (TRUE != gtk_tree_model_get_iter (tm, &iter, tp)) | ||
1480 | { | ||
1481 | GNUNET_break (0); | ||
1482 | gtk_tree_path_free (tp); | ||
1483 | return; | ||
1484 | } | ||
1485 | gtk_tree_path_free (tp); | ||
1486 | gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1); | ||
1487 | if (uri != NULL) | ||
1488 | GNUNET_FS_uri_destroy (uri); | ||
1489 | if (meta != NULL) | ||
1490 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
1491 | gtk_tree_row_reference_free (sr->rr); | ||
1492 | (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter); | ||
1493 | GNUNET_free (sr); | ||
1494 | } | ||
1495 | |||
1496 | |||
1378 | /** | 1497 | /** |
1379 | * Stop completed downloads (or those that failed). Should | 1498 | * Stop completed downloads (or those that failed). Should |
1380 | * iterate over the underlying tree store and stop all | 1499 | * iterate over the underlying tree store and stop all |
@@ -1924,44 +2043,6 @@ update_search_result (struct SearchResult *sr, | |||
1924 | } | 2043 | } |
1925 | 2044 | ||
1926 | 2045 | ||
1927 | static void | ||
1928 | free_search_result (struct SearchResult *sr) | ||
1929 | { | ||
1930 | GtkTreePath *tp; | ||
1931 | GtkTreeModel *tm; | ||
1932 | GtkTreeIter iter; | ||
1933 | struct GNUNET_FS_Uri *uri; | ||
1934 | struct GNUNET_CONTAINER_MetaData *meta; | ||
1935 | |||
1936 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1937 | "Freeing a search result SR=%p\n", sr); | ||
1938 | |||
1939 | if (sr == NULL) | ||
1940 | { | ||
1941 | GNUNET_break (0); | ||
1942 | return; | ||
1943 | } | ||
1944 | GNUNET_assert (sr->rr != NULL); | ||
1945 | tp = gtk_tree_row_reference_get_path (sr->rr); | ||
1946 | GNUNET_assert (tp != NULL); | ||
1947 | tm = gtk_tree_row_reference_get_model (sr->rr); | ||
1948 | GNUNET_assert (tm != NULL); | ||
1949 | if (TRUE != gtk_tree_model_get_iter (tm, &iter, tp)) | ||
1950 | { | ||
1951 | GNUNET_break (0); | ||
1952 | gtk_tree_path_free (tp); | ||
1953 | return; | ||
1954 | } | ||
1955 | gtk_tree_path_free (tp); | ||
1956 | gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1); | ||
1957 | if (uri != NULL) | ||
1958 | GNUNET_FS_uri_destroy (uri); | ||
1959 | if (meta != NULL) | ||
1960 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
1961 | gtk_tree_row_reference_free (sr->rr); | ||
1962 | (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter); | ||
1963 | GNUNET_free (sr); | ||
1964 | } | ||
1965 | 2046 | ||
1966 | 2047 | ||
1967 | /** | 2048 | /** |
@@ -2364,188 +2445,6 @@ GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy, | |||
2364 | gtk_list_store_clear (ms); | 2445 | gtk_list_store_clear (ms); |
2365 | } | 2446 | } |
2366 | 2447 | ||
2367 | static void | ||
2368 | copy_metadata_to_clipboard (GtkTreeModel * model, GtkTreePath * path, | ||
2369 | GtkTreeIter * iter, gpointer user_data) | ||
2370 | { | ||
2371 | gchar *type, *value; | ||
2372 | GList **l = (GList **) user_data; | ||
2373 | |||
2374 | gtk_tree_model_get (model, iter, 2, &type, 3, &value, -1); | ||
2375 | |||
2376 | *l = g_list_prepend (*l, type); | ||
2377 | *l = g_list_prepend (*l, value); | ||
2378 | } | ||
2379 | |||
2380 | void | ||
2381 | metadata_copy_selection_activated (GtkMenuItem * menuitem, gpointer user_data) | ||
2382 | { | ||
2383 | GtkBuilder *builder; | ||
2384 | GtkTreeView *tree; | ||
2385 | GtkClipboard *cb; | ||
2386 | GList *pairs = NULL, *l, *next, *value, *type; | ||
2387 | guint total_len; | ||
2388 | gchar *s, *p; | ||
2389 | |||
2390 | builder = GTK_BUILDER (user_data); | ||
2391 | tree = | ||
2392 | GTK_TREE_VIEW (gtk_builder_get_object | ||
2393 | (builder, "GNUNET_GTK_main_window_metadata_treeview")); | ||
2394 | |||
2395 | gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree), | ||
2396 | copy_metadata_to_clipboard, &pairs); | ||
2397 | |||
2398 | total_len = 0; | ||
2399 | pairs = g_list_reverse (pairs); | ||
2400 | for (l = pairs; l; l = next) | ||
2401 | { | ||
2402 | type = l; | ||
2403 | value = l->next; | ||
2404 | if (!value) | ||
2405 | break; | ||
2406 | next = value->next; | ||
2407 | total_len += | ||
2408 | strlen ((gchar *) type->data) + strlen ((gchar *) value->data) + | ||
2409 | 2 /* ": " */ + (next ? 1 : 0) /* "\n" */ ; | ||
2410 | } | ||
2411 | if (total_len > 0) | ||
2412 | { | ||
2413 | total_len += 1; /* "\0" */ | ||
2414 | s = g_new0 (gchar, total_len); | ||
2415 | p = s; | ||
2416 | for (l = pairs; l; l = next) | ||
2417 | { | ||
2418 | type = l; | ||
2419 | value = l->next; | ||
2420 | if (value) | ||
2421 | { | ||
2422 | next = value->next; | ||
2423 | p = g_stpcpy (p, (gchar *) type->data); | ||
2424 | p = g_stpcpy (p, ": "); | ||
2425 | p = g_stpcpy (p, (gchar *) value->data); | ||
2426 | if (next) | ||
2427 | p = g_stpcpy (p, "\n"); | ||
2428 | } | ||
2429 | else | ||
2430 | next = NULL; | ||
2431 | } | ||
2432 | } | ||
2433 | g_list_foreach (pairs, (GFunc) g_free, NULL); | ||
2434 | g_list_free (pairs); | ||
2435 | pairs = NULL; | ||
2436 | |||
2437 | if (total_len > 0) | ||
2438 | { | ||
2439 | cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); | ||
2440 | gtk_clipboard_set_text (cb, s, -1); | ||
2441 | gtk_clipboard_store (cb); | ||
2442 | g_free (s); | ||
2443 | } | ||
2444 | } | ||
2445 | |||
2446 | void | ||
2447 | metadata_menu_popup_position (GtkMenu * menu, gint * x, gint * y, | ||
2448 | gboolean * push_in, gpointer user_data) | ||
2449 | { | ||
2450 | GtkBuilder *builder; | ||
2451 | GtkTreeView *tree; | ||
2452 | GtkTreeSelection *sel; | ||
2453 | GList *rows; | ||
2454 | GtkTreePath *p; | ||
2455 | GtkAllocation tree_allocation; | ||
2456 | GdkWindow *main_window_gdk; | ||
2457 | gint mwg_x, mwg_y, t_x, t_y, popup_x, popup_y; | ||
2458 | |||
2459 | builder = GTK_BUILDER (user_data); | ||
2460 | |||
2461 | tree = | ||
2462 | GTK_TREE_VIEW (gtk_builder_get_object | ||
2463 | (builder, "GNUNET_GTK_main_window_metadata_treeview")); | ||
2464 | |||
2465 | gtk_widget_get_allocation (GTK_WIDGET (tree), &tree_allocation); | ||
2466 | |||
2467 | main_window_gdk = gtk_widget_get_window (GTK_WIDGET (tree)); | ||
2468 | |||
2469 | gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y); | ||
2470 | |||
2471 | t_x = mwg_x + tree_allocation.x; | ||
2472 | t_y = mwg_y + tree_allocation.y; | ||
2473 | popup_x = t_x; | ||
2474 | popup_y = t_y; | ||
2475 | |||
2476 | sel = gtk_tree_view_get_selection (tree); | ||
2477 | |||
2478 | rows = gtk_tree_selection_get_selected_rows (sel, NULL); | ||
2479 | |||
2480 | if (rows->data) | ||
2481 | { | ||
2482 | GdkRectangle r; | ||
2483 | |||
2484 | p = (GtkTreePath *) rows->data; | ||
2485 | gtk_tree_view_get_cell_area (tree, p, NULL, &r); | ||
2486 | popup_x += r.x; | ||
2487 | popup_y += r.y; | ||
2488 | } | ||
2489 | |||
2490 | g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL); | ||
2491 | g_list_free (rows); | ||
2492 | *x = popup_x; | ||
2493 | *y = popup_y; | ||
2494 | *push_in = FALSE; | ||
2495 | } | ||
2496 | |||
2497 | static void | ||
2498 | do_metadata_popup_menu (GtkWidget * widget, GdkEventButton * event, | ||
2499 | gpointer user_data) | ||
2500 | { | ||
2501 | GtkMenu *menu; | ||
2502 | GtkBuilder *builder; | ||
2503 | int button, event_time; | ||
2504 | GtkMenuPositionFunc mpf = NULL; | ||
2505 | |||
2506 | builder = GTK_BUILDER (user_data); | ||
2507 | |||
2508 | menu = GTK_MENU (gtk_builder_get_object (builder, "metadata_popup_menu")); | ||
2509 | |||
2510 | if (event) | ||
2511 | { | ||
2512 | button = event->button; | ||
2513 | event_time = event->time; | ||
2514 | } | ||
2515 | else | ||
2516 | { | ||
2517 | button = 0; | ||
2518 | event_time = gtk_get_current_event_time (); | ||
2519 | } | ||
2520 | |||
2521 | gtk_menu_popup (menu, NULL, NULL, mpf, user_data, button, event_time); | ||
2522 | } | ||
2523 | |||
2524 | gboolean | ||
2525 | GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb (GtkWidget * | ||
2526 | widget, | ||
2527 | GdkEventButton * | ||
2528 | event, | ||
2529 | gpointer | ||
2530 | user_data) | ||
2531 | { | ||
2532 | /* Ignore double-clicks and triple-clicks */ | ||
2533 | if (event->button == 3 && event->type == GDK_BUTTON_PRESS) | ||
2534 | { | ||
2535 | do_metadata_popup_menu (widget, event, user_data); | ||
2536 | return TRUE; | ||
2537 | } | ||
2538 | |||
2539 | return FALSE; | ||
2540 | } | ||
2541 | |||
2542 | gboolean | ||
2543 | GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb (GtkWidget * widget, | ||
2544 | gpointer user_data) | ||
2545 | { | ||
2546 | do_metadata_popup_menu (widget, NULL, user_data); | ||
2547 | return TRUE; | ||
2548 | } | ||
2549 | 2448 | ||
2550 | 2449 | ||
2551 | /* end of gnunet-fs-gtk-event_handler.c */ | 2450 | /* end of gnunet-fs-gtk-event_handler.c */ |