1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  File-Roller
5  *
6  *  Copyright (C) 2007 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <math.h>
24 #include <string.h>
25 #include <glib/gi18n.h>
26 #include <gio/gio.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdk.h>
29 #ifdef GDK_WINDOWING_X11
30 # include <gdk/gdkx.h>
31 #endif
32 #include <gdk/gdkkeysyms.h>
33 #include <gdk-pixbuf/gdk-pixbuf.h>
34 #ifdef ENABLE_NOTIFICATION
35 #  include <libnotify/notify.h>
36 #endif
37 #include "dlg-batch-add.h"
38 #include "dlg-delete.h"
39 #include "dlg-extract.h"
40 #include "dlg-open-with.h"
41 #include "dlg-ask-password.h"
42 #include "dlg-package-installer.h"
43 #include "dlg-update.h"
44 #include "eggtreemultidnd.h"
45 #include "fr-marshal.h"
46 #include "fr-list-model.h"
47 #include "fr-location-bar.h"
48 #include "fr-archive.h"
49 #include "fr-command.h"
50 #include "fr-error.h"
51 #include "fr-new-archive-dialog.h"
52 #include "fr-window.h"
53 #include "fr-window-actions-entries.h"
54 #include "file-data.h"
55 #include "file-utils.h"
56 #include "glib-utils.h"
57 #include "gth-icon-cache.h"
58 #include "fr-init.h"
59 #include "gtk-utils.h"
60 #include "open-file.h"
61 #include "typedefs.h"
62 
63 #define LAST_OUTPUT_SCHEMA_NAME "LastOutput"
64 #define MAX_HISTORY_LEN 5
65 #define ACTIVITY_DELAY 100
66 #define ACTIVITY_PULSE_STEP (0.033)
67 #define MAX_MESSAGE_LENGTH 50
68 
69 #define PROGRESS_DIALOG_DEFAULT_WIDTH 500
70 #define PROGRESS_TIMEOUT_MSECS 1000
71 #define PROGRESS_BAR_HEIGHT 10
72 #undef  LOG_PROGRESS
73 
74 #define HIDE_PROGRESS_TIMEOUT_MSECS 500
75 #define DEFAULT_NAME_COLUMN_WIDTH 250
76 #define OTHER_COLUMNS_WIDTH 100
77 #define RECENT_ITEM_MAX_WIDTH 25
78 
79 #define DEF_WIN_WIDTH 600
80 #define DEF_WIN_HEIGHT 480
81 #define DEF_SIDEBAR_WIDTH 200
82 
83 #define FILE_LIST_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
84 #define DIR_TREE_ICON_SIZE GTK_ICON_SIZE_MENU
85 
86 #define BAD_CHARS "/\\*"
87 
88 #define XDS_FILENAME "xds.txt"
89 #define MAX_XDS_ATOM_VAL_LEN 4096
90 #define XDS_ATOM   gdk_atom_intern  ("XdndDirectSave0", FALSE)
91 #define TEXT_ATOM  gdk_atom_intern  ("text/plain", FALSE)
92 #define OCTET_ATOM gdk_atom_intern  ("application/octet-stream", FALSE)
93 #define XFR_ATOM   gdk_atom_intern  ("XdndFileRoller0", FALSE)
94 
95 #define FR_CLIPBOARD (gdk_atom_intern_static_string ("_FILE_ROLLER_SPECIAL_CLIPBOARD"))
96 #define FR_SPECIAL_URI_LIST (gdk_atom_intern_static_string ("application/file-roller-uri-list"))
97 
98 static GtkTargetEntry clipboard_targets[] = {
99 	{ "application/file-roller-uri-list", 0, 1 }
100 };
101 
102 static GtkTargetEntry target_table[] = {
103 	{ "XdndFileRoller0", 0, 0 },
104 	{ "text/uri-list", 0, 1 },
105 };
106 
107 static GtkTargetEntry folder_tree_targets[] = {
108 	{ "XdndFileRoller0", 0, 0 },
109 	{ "XdndDirectSave0", 0, 2 }
110 };
111 
112 
113 typedef struct {
114 	FrBatchActionType type;
115 	void *            data;
116 	GFreeFunc         free_func;
117 } FrBatchAction;
118 
119 
120 typedef struct {
121 	FrWindow    *window;
122 	GList       *file_list;
123 	GFile       *destination;
124 	char        *base_dir;
125 	gboolean     skip_older;
126 	FrOverwrite  overwrite;
127 	gboolean     junk_paths;
128 	char        *password;
129 	gboolean     ask_to_open_destination;
130 	gboolean     avoid_tarbombs;
131 } ExtractData;
132 
133 
134 typedef enum {
135 	FR_WINDOW_AREA_MENUBAR,
136 	FR_WINDOW_AREA_TOOLBAR,
137 	FR_WINDOW_AREA_LOCATIONBAR,
138 	FR_WINDOW_AREA_CONTENTS,
139 	FR_WINDOW_AREA_FILTERBAR,
140 	FR_WINDOW_AREA_STATUSBAR,
141 } FrWindowArea;
142 
143 
144 typedef enum {
145 	DIALOG_RESPONSE_NONE = 1,
146 	DIALOG_RESPONSE_OPEN_ARCHIVE,
147 	DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER,
148 } DialogResponse;
149 
150 
151 /* -- FrClipboardData -- */
152 
153 
154 typedef struct {
155 	int            refs;
156 	GFile         *file;
157 	char          *password;
158 	FrClipboardOp  op;
159 	char          *base_dir;
160 	GList         *files;
161 	GFile         *tmp_dir;
162 	char          *current_dir;
163 } FrClipboardData;
164 
165 
166 static FrClipboardData*
fr_clipboard_data_new(void)167 fr_clipboard_data_new (void)
168 {
169 	FrClipboardData *data;
170 
171 	data = g_new0 (FrClipboardData, 1);
172 	data->refs = 1;
173 
174 	return data;
175 }
176 
177 
178 static FrClipboardData *
fr_clipboard_data_ref(FrClipboardData * clipboard_data)179 fr_clipboard_data_ref (FrClipboardData *clipboard_data)
180 {
181 	clipboard_data->refs++;
182 	return clipboard_data;
183 }
184 
185 
186 static void
fr_clipboard_data_unref(FrClipboardData * clipboard_data)187 fr_clipboard_data_unref (FrClipboardData *clipboard_data)
188 {
189 	if (clipboard_data == NULL)
190 		return;
191 	if (--clipboard_data->refs > 0)
192 		return;
193 
194 	_g_object_unref (clipboard_data->file);
195 	g_free (clipboard_data->password);
196 	g_free (clipboard_data->base_dir);
197 	_g_object_unref (clipboard_data->tmp_dir);
198 	g_free (clipboard_data->current_dir);
199 	g_list_foreach (clipboard_data->files, (GFunc) g_free, NULL);
200 	g_list_free (clipboard_data->files);
201 	g_free (clipboard_data);
202 }
203 
204 
205 static void
fr_clipboard_data_set_password(FrClipboardData * clipboard_data,const char * password)206 fr_clipboard_data_set_password (FrClipboardData *clipboard_data,
207 				const char      *password)
208 {
209 	if (clipboard_data->password != password)
210 		g_free (clipboard_data->password);
211 	if (password != NULL)
212 		clipboard_data->password = g_strdup (password);
213 }
214 
215 
216 /**/
217 
218 
219 G_DEFINE_TYPE (FrWindow, fr_window, GTK_TYPE_APPLICATION_WINDOW)
220 
221 
222 enum {
223 	ARCHIVE_LOADED,
224 	PROGRESS,
225 	READY,
226 	LAST_SIGNAL
227 };
228 
229 static guint fr_window_signals[LAST_SIGNAL] = { 0 };
230 
231 struct _FrWindowPrivate {
232 	GtkWidget         *layout;
233 	GtkWidget         *contents;
234 	GtkWidget         *list_view;
235 	GtkListStore      *list_store;
236 	GtkWidget         *tree_view;
237 	GtkTreeStore      *tree_store;
238 	GtkWidget         *headerbar;
239 	GtkWidget         *location_bar;
240 	GtkWidget         *location_entry;
241 	GtkWidget         *location_label;
242 	GtkWidget         *filter_bar;
243 	GtkWidget         *filter_entry;
244 	GtkWidget         *paned;
245 	GtkWidget         *sidepane;
246 	GtkTreePath       *tree_hover_path;
247 	GtkTreePath       *list_hover_path;
248 	GtkTreeViewColumn *filename_column;
249 	GtkWindowGroup    *window_group;
250 	GtkAccelGroup     *accel_group;
251 	GHashTable        *named_dialogs;
252 
253 	gboolean         filter_mode;
254 	gint             current_view_length;
255 
256 	GtkWidget *      up_arrows[5];
257 	GtkWidget *      down_arrows[5];
258 
259 	FrAction         action;
260 	gboolean         archive_present;
261 	gboolean         archive_new;        /* A new archive has been created
262 					      * but it doesn't contain any
263 					      * file yet.  The real file will
264 					      * be created only when the user
265 					      * adds some file to the
266 					      * archive.*/
267 	gboolean         reload_archive;
268 
269 	GFile *          archive_file;
270 	GFile *          open_default_dir;    /* default directory to be used
271 					       * in the Open dialog. */
272 	GFile *          add_default_dir;     /* default directory to be used
273 					       * in the Add dialog. */
274 	GFile *          extract_default_dir; /* default directory to be used
275 					       * in the Extract dialog. */
276 	gboolean         freeze_default_dir;
277 	gboolean         destroy_with_error_dialog;
278 	gboolean         destroy_with_confirmation_dialog;
279 
280 	FrBatchAction    current_action;
281 
282 	gboolean         give_focus_to_the_list;
283 	gboolean         single_click;
284 	GtkTreePath     *path_clicked;
285 
286 	FrWindowSortMethod sort_method;
287 	GtkSortType      sort_type;
288 
289 	char *           last_location;
290 
291 	gboolean         view_sidebar;
292 	FrWindowListMode list_mode;
293 	FrWindowListMode last_list_mode;
294 	GList *          history;
295 	GList *          history_current;
296 	char *           password;
297 	char *           second_password;
298 	gboolean         encrypt_header;
299 	FrCompression    compression;
300 	guint            volume_size;
301 
302 	guint            activity_timeout_handle;   /* activity timeout
303 						     * handle. */
304 	gint             activity_ref;              /* when > 0 some activity
305 						     * is present. */
306 
307 	gboolean         stoppable;
308 	gboolean         closing;
309 	gboolean         notify;
310 	gboolean         populating_file_list;
311 
312 	FrClipboardData *clipboard_data;
313 	FrClipboardData *copy_data;
314 
315 	FrArchive       *copy_from_archive;
316 	GFile           *saving_file;
317 
318 	GtkWidget        *file_popup_menu;
319 	GtkWidget        *folder_popup_menu;
320 	GtkWidget        *sidebar_folder_popup_menu;
321 	GtkWidget        *mitem_recents_menu;
322 
323 	/* dragged files data */
324 
325 	GFile            *drag_destination_folder;
326 	char             *drag_base_dir;
327 	GError           *drag_error;
328 	GList            *drag_file_list;        /* the list of files we are
329 					 	  * dragging*/
330 	gboolean	  dnd_extract_is_running;
331 	gboolean	  dnd_extract_finished_with_error;
332 
333 	/* progress dialog data */
334 
335 	GtkWidget        *progress_dialog;
336 	GtkWidget        *pd_action;
337 	GtkWidget        *pd_message;
338 	GtkWidget        *pd_progress_bar;
339 	GtkWidget        *pd_progress_box;
340 	gboolean          progress_pulse;
341 	guint             progress_timeout;  /* Timeout to display the progress dialog. */
342 	guint             hide_progress_timeout;  /* Timeout to hide the progress dialog. */
343 	GFile            *pd_last_archive;
344 	GFile            *working_archive;
345 	double            pd_last_fraction;
346 	char             *pd_last_message;
347 	gboolean          use_progress_dialog;
348 	char             *custom_action_message;
349 
350 	/* update dialog data */
351 
352 	gpointer          update_dialog;
353 	GList            *open_files;
354 
355 	/* batch mode data */
356 
357 	gboolean          batch_mode;          /* whether we are in a non interactive
358 					 	* mode. */
359 	GList            *batch_action_list;   /* FrBatchAction * elements */
360 	GList            *batch_action;        /* current action. */
361 	char             *batch_title;
362 
363 	/* misc */
364 
365 	GCancellable     *cancellable;
366 
367 	GSettings        *settings_listing;
368 	GSettings        *settings_ui;
369 	GSettings        *settings_general;
370 	GSettings        *settings_dialogs;
371 	GSettings        *settings_nautilus;
372 
373 	gulong            theme_changed_handler_id;
374 	gboolean          update_dropped_files;
375 	gboolean          batch_adding_one_file;
376 
377 	GtkWindow        *load_error_parent_window;
378 	gboolean          showing_error_dialog;
379 
380 	GthIconCache     *list_icon_cache;
381 	GthIconCache     *tree_icon_cache;
382 
383 	GFile            *last_extraction_destination;
384 	GList            *last_extraction_files_first_level; /* GFile list */
385 };
386 
387 
388 /* -- fr_window_free_private_data -- */
389 
390 
391 static void
fr_batch_action_free(FrBatchAction * action)392 fr_batch_action_free (FrBatchAction *action) {
393 	if ((action->data != NULL) && (action->free_func != NULL))
394 		(*action->free_func) (action->data);
395 	g_free (action);
396 }
397 
398 
399 static void
fr_window_free_batch_data(FrWindow * window)400 fr_window_free_batch_data (FrWindow *window)
401 {
402 	GList *scan;
403 
404 	for (scan = window->priv->batch_action_list; scan; scan = scan->next)
405 		fr_batch_action_free ((FrBatchAction *) scan->data);
406 	g_list_free (window->priv->batch_action_list);
407 	window->priv->batch_action_list = NULL;
408 	window->priv->batch_action = NULL;
409 
410 	fr_window_reset_current_action (window);
411 }
412 
413 
414 static GdkAtom
_fr_window_get_clipboard_name(FrWindow * window)415 _fr_window_get_clipboard_name (FrWindow *window)
416 {
417 #ifdef GDK_WINDOWING_X11
418 	if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window))))
419 		return FR_CLIPBOARD;
420 #endif
421 	return GDK_SELECTION_CLIPBOARD;
422 }
423 
424 
425 static void
fr_window_clipboard_remove_file_list(FrWindow * window,GList * file_list)426 fr_window_clipboard_remove_file_list (FrWindow *window,
427 				      GList    *file_list)
428 {
429 	GList *scan1;
430 
431 	if (window->priv->copy_data == NULL)
432 		return;
433 
434 	if (file_list == NULL) {
435 		fr_clipboard_data_unref	 (window->priv->copy_data);
436 		window->priv->copy_data = NULL;
437 		return;
438 	}
439 
440 	for (scan1 = file_list; scan1; scan1 = scan1->next) {
441 		const char *name1 = scan1->data;
442 		GList      *scan2;
443 
444 		for (scan2 = window->priv->copy_data->files; scan2;) {
445 			const char *name2 = scan2->data;
446 
447 			if (strcmp (name1, name2) == 0) {
448 				GList *tmp = scan2->next;
449 				window->priv->copy_data->files = g_list_remove_link (window->priv->copy_data->files, scan2);
450 				g_free (scan2->data);
451 				g_list_free (scan2);
452 				scan2 = tmp;
453 			}
454 			else
455 				scan2 = scan2->next;
456 		}
457 	}
458 
459 	if (window->priv->copy_data->files == NULL) {
460 		fr_clipboard_data_unref (window->priv->copy_data);
461 		window->priv->copy_data = NULL;
462 		gtk_clipboard_clear (gtk_widget_get_clipboard (GTK_WIDGET (window), _fr_window_get_clipboard_name (window)));
463 	}
464 }
465 
466 
467 static void
fr_window_history_clear(FrWindow * window)468 fr_window_history_clear (FrWindow *window)
469 {
470 	if (window->priv->history != NULL)
471 		_g_string_list_free (window->priv->history);
472 	window->priv->history = NULL;
473 	window->priv->history_current = NULL;
474 	g_free (window->priv->last_location);
475 	window->priv->last_location = NULL;
476 }
477 
478 
479 static void
fr_window_free_open_files(FrWindow * window)480 fr_window_free_open_files (FrWindow *window)
481 {
482 	GList *scan;
483 
484 	for (scan = window->priv->open_files; scan; scan = scan->next) {
485 		OpenFile *file = scan->data;
486 
487 		if (file->monitor != NULL)
488 			g_file_monitor_cancel (file->monitor);
489 		open_file_free (file);
490 	}
491 	g_list_free (window->priv->open_files);
492 	window->priv->open_files = NULL;
493 }
494 
495 
496 static void
fr_window_free_private_data(FrWindow * window)497 fr_window_free_private_data (FrWindow *window)
498 {
499 	if (window->priv->activity_timeout_handle != 0) {
500 		g_source_remove (window->priv->activity_timeout_handle);
501 		window->priv->activity_timeout_handle = 0;
502 	}
503 
504 	if (window->priv->progress_timeout != 0) {
505 		g_source_remove (window->priv->progress_timeout);
506 		window->priv->progress_timeout = 0;
507 	}
508 
509 	if (window->priv->hide_progress_timeout != 0) {
510 		g_source_remove (window->priv->hide_progress_timeout);
511 		window->priv->hide_progress_timeout = 0;
512 	}
513 
514 	if (window->priv->theme_changed_handler_id != 0)
515 		g_signal_handler_disconnect (gtk_icon_theme_get_default (), window->priv->theme_changed_handler_id);
516 
517 	fr_window_history_clear (window);
518 
519 	_g_object_unref (window->priv->open_default_dir);
520 	_g_object_unref (window->priv->add_default_dir);
521 	_g_object_unref (window->priv->extract_default_dir);
522 	_g_object_unref (window->priv->archive_file);
523 	_g_object_unref (window->priv->last_extraction_destination);
524 
525 	_g_object_list_unref (window->priv->last_extraction_files_first_level);
526 	window->priv->last_extraction_files_first_level = NULL;
527 
528 	g_free (window->priv->password);
529 	g_free (window->priv->second_password);
530 	g_free (window->priv->custom_action_message);
531 
532 	g_object_unref (window->priv->list_store);
533 
534 	if (window->priv->clipboard_data != NULL) {
535 		fr_clipboard_data_unref (window->priv->clipboard_data);
536 		window->priv->clipboard_data = NULL;
537 	}
538 	if (window->priv->copy_data != NULL) {
539 		fr_clipboard_data_unref (window->priv->copy_data);
540 		window->priv->copy_data = NULL;
541 	}
542 	if (window->priv->copy_from_archive != NULL) {
543 		g_object_unref (window->priv->copy_from_archive);
544 		window->priv->copy_from_archive = NULL;
545 	}
546 
547 	_g_object_unref (window->priv->saving_file);
548 
549 	fr_window_free_open_files (window);
550 
551 	g_clear_error (&window->priv->drag_error);
552 	_g_string_list_free (window->priv->drag_file_list);
553 	window->priv->drag_file_list = NULL;
554 
555 	g_free (window->priv->last_location);
556 
557 	fr_window_free_batch_data (window);
558 	g_free (window->priv->batch_title);
559 
560 	_g_object_unref (window->priv->pd_last_archive);
561 	g_free (window->priv->pd_last_message);
562 
563 	g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE, window->priv->last_list_mode);
564 
565 	_g_object_unref (window->priv->settings_listing);
566 	_g_object_unref (window->priv->settings_ui);
567 	_g_object_unref (window->priv->settings_general);
568 	_g_object_unref (window->priv->settings_dialogs);
569 	_g_object_unref (window->priv->settings_nautilus);
570 
571 	_g_object_unref (window->priv->cancellable);
572 	g_hash_table_unref (window->priv->named_dialogs);
573 	g_object_unref (window->priv->window_group);
574 	g_object_unref (window->priv->accel_group);
575 }
576 
577 
578 void
fr_window_close(FrWindow * window)579 fr_window_close (FrWindow *window)
580 {
581 	if (window->priv->activity_ref > 0)
582 		return;
583 
584 	if (window->priv->closing)
585 		return;
586 
587 	window->priv->closing = TRUE;
588 
589 	if (gtk_widget_get_realized (GTK_WIDGET (window))) {
590 		int width, height;
591 
592 		gtk_window_get_size (GTK_WINDOW (window), &width, &height);
593 		g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH, width);
594 		g_settings_set_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT, height);
595 
596 		width = gtk_paned_get_position (GTK_PANED (window->priv->paned));
597 		if (width > 0)
598 			g_settings_set_int (window->priv->settings_ui, PREF_UI_SIDEBAR_WIDTH, width);
599 
600 		width = gtk_tree_view_column_get_width (window->priv->filename_column);
601 		if (width > 0)
602 			g_settings_set_int (window->priv->settings_listing, PREF_LISTING_NAME_COLUMN_WIDTH, width);
603 	}
604 
605 	gtk_widget_destroy (GTK_WIDGET (window));
606 }
607 
608 
609 #define DIALOG_NAME_KEY "fr_dialog_name"
610 
611 
612 static void
unset_dialog(GtkWidget * object,gpointer user_data)613 unset_dialog (GtkWidget *object,
614               gpointer   user_data)
615 {
616 	FrWindow   *window = user_data;
617 	const char *dialog_name;
618 
619 	dialog_name = g_object_get_data (G_OBJECT (object), DIALOG_NAME_KEY);
620 	if (dialog_name != NULL)
621 		g_hash_table_remove (window->priv->named_dialogs, dialog_name);
622 }
623 
624 
625 void
fr_window_set_dialog(FrWindow * window,const char * dialog_name,GtkWidget * dialog)626 fr_window_set_dialog (FrWindow   *window,
627 		      const char *dialog_name,
628 		      GtkWidget  *dialog)
629 {
630 	g_object_set_data (G_OBJECT (dialog), DIALOG_NAME_KEY, (gpointer) _g_str_get_static (dialog_name));
631 	g_hash_table_insert (window->priv->named_dialogs, (gpointer) dialog_name, dialog);
632 	g_signal_connect (dialog,
633 			  "destroy",
634 			  G_CALLBACK (unset_dialog),
635 			  window);
636 }
637 
638 
639 gboolean
fr_window_present_dialog_if_created(FrWindow * window,const char * dialog_name)640 fr_window_present_dialog_if_created (FrWindow   *window,
641 				     const char *dialog_name)
642 {
643 	GtkWidget *dialog;
644 
645 	dialog = g_hash_table_lookup (window->priv->named_dialogs, dialog_name);
646 	if (dialog != NULL) {
647 		gtk_window_present (GTK_WINDOW (dialog));
648 		return TRUE;
649 	}
650 
651 	return FALSE;
652 }
653 
654 
655 static void
fr_window_finalize(GObject * object)656 fr_window_finalize (GObject *object)
657 {
658 	FrWindow *window = FR_WINDOW (object);
659 
660 	fr_window_free_open_files (window);
661 
662 	if (window->archive != NULL) {
663 		g_object_unref (window->archive);
664 		window->archive = NULL;
665 	}
666 
667 	if (window->priv != NULL) {
668 		fr_window_free_private_data (window);
669 		g_free (window->priv);
670 		window->priv = NULL;
671 	}
672 
673 	G_OBJECT_CLASS (fr_window_parent_class)->finalize (object);
674 }
675 
676 
677 
678 static void fr_window_update_file_list (FrWindow *window,
679 					gboolean  update_view);
680 static void fr_window_update_dir_tree  (FrWindow *window);
681 
682 
683 static void
fr_window_enable_action(FrWindow * window,const char * action_name,gboolean enabled)684 fr_window_enable_action (FrWindow   *window,
685 			 const char *action_name,
686 			 gboolean    enabled)
687 {
688 	GAction *action;
689 
690 	action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name);
691 	if (action != NULL)
692 		g_object_set (action, "enabled", enabled, NULL);
693 }
694 
695 
696 static void
fr_window_set_action_state(FrWindow * window,const char * action_name,gboolean active)697 fr_window_set_action_state (FrWindow   *window,
698 			    const char *action_name,
699 			    gboolean    active)
700 {
701 	GAction *action;
702 
703 	action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name);
704 	if (action != NULL)
705 		g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (active));
706 }
707 
708 
709 static void
fr_window_change_action_state(FrWindow * window,const char * action_name,gboolean value)710 fr_window_change_action_state (FrWindow   *window,
711 			       const char *action_name,
712 			       gboolean    value)
713 {
714 	GAction  *action;
715 	GVariant *old_state;
716 	GVariant *new_state;
717 
718 	action = g_action_map_lookup_action (G_ACTION_MAP (window), action_name);
719 	g_return_if_fail (action != NULL);
720 
721 	old_state = g_action_get_state (action);
722 	new_state = g_variant_new_boolean (value);
723 	if ((old_state == NULL) || ! g_variant_equal (old_state, new_state))
724 		g_action_change_state (action, new_state);
725 	else
726 		g_variant_unref (new_state);
727 
728 	if (old_state != NULL)
729 		g_variant_unref (old_state);
730 }
731 
732 
733 static void
fr_window_update_paste_command_sensitivity(FrWindow * window,GtkClipboard * clipboard)734 fr_window_update_paste_command_sensitivity (FrWindow     *window,
735 					    GtkClipboard *clipboard)
736 {
737 	gboolean running;
738 	gboolean no_archive;
739 	gboolean ro;
740 
741 	if (window->priv->closing)
742 		return;
743 
744 	if (clipboard == NULL)
745 		clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), _fr_window_get_clipboard_name (window));
746 	if (clipboard == NULL)
747 		return;
748 
749 	running    = window->priv->activity_ref > 0;
750 	no_archive = (window->archive == NULL) || ! window->priv->archive_present;
751 	ro         = ! no_archive && window->archive->read_only;
752 
753 #if 0
754 	set_sensitive (window, "Paste",
755 		       ! no_archive
756 		       && ! ro
757 		       && ! running
758 		       && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES)
759 		       && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)
760 		       && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST));
761 #endif
762 
763 	fr_window_enable_action (window, "edit-paste",
764 				 ! no_archive
765 				 && ! ro
766 				 && ! running
767 				 && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES)
768 				 && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT)
769 				 && gtk_clipboard_wait_is_target_available (clipboard, FR_SPECIAL_URI_LIST));
770 }
771 
772 
773 static void
clipboard_owner_change_cb(GtkClipboard * clipboard,GdkEvent * event,gpointer user_data)774 clipboard_owner_change_cb (GtkClipboard *clipboard,
775 			   GdkEvent     *event,
776 			   gpointer      user_data)
777 {
778 	fr_window_update_paste_command_sensitivity ((FrWindow *) user_data, clipboard);
779 }
780 
781 
782 static void
fr_window_realize(GtkWidget * widget)783 fr_window_realize (GtkWidget *widget)
784 {
785 	FrWindow     *window = FR_WINDOW (widget);
786 	GIcon        *icon;
787 	GtkClipboard *clipboard;
788 
789 	GTK_WIDGET_CLASS (fr_window_parent_class)->realize (widget);
790 
791 	window->priv->list_icon_cache = gth_icon_cache_new_for_widget (GTK_WIDGET (window), GTK_ICON_SIZE_LARGE_TOOLBAR);
792 	window->priv->tree_icon_cache = gth_icon_cache_new_for_widget (GTK_WIDGET (window), GTK_ICON_SIZE_MENU);
793 
794 	icon = g_content_type_get_icon ("text/plain");
795 	gth_icon_cache_set_fallback (window->priv->list_icon_cache, icon);
796 	gth_icon_cache_set_fallback (window->priv->tree_icon_cache, icon);
797 	g_object_unref (icon);
798 
799 	clipboard = gtk_widget_get_clipboard (widget, _fr_window_get_clipboard_name (window));
800 	g_signal_connect (clipboard,
801 			  "owner_change",
802 			  G_CALLBACK (clipboard_owner_change_cb),
803 			  window);
804 
805 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
806 					      g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD),
807 					      g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE));
808 
809 	fr_window_update_dir_tree (window);
810 	fr_window_update_file_list (window, TRUE);
811 }
812 
813 
814 static void
fr_window_unrealize(GtkWidget * widget)815 fr_window_unrealize (GtkWidget *widget)
816 {
817 	FrWindow     *window = FR_WINDOW (widget);
818 	GtkClipboard *clipboard;
819 
820 	gth_icon_cache_free (window->priv->list_icon_cache);
821 	window->priv->list_icon_cache = NULL;
822 
823 	gth_icon_cache_free (window->priv->tree_icon_cache);
824 	window->priv->tree_icon_cache = NULL;
825 
826 	clipboard = gtk_widget_get_clipboard (widget, _fr_window_get_clipboard_name (window));
827 	g_signal_handlers_disconnect_by_func (clipboard,
828 					      G_CALLBACK (clipboard_owner_change_cb),
829 					      window);
830 
831 	GTK_WIDGET_CLASS (fr_window_parent_class)->unrealize (widget);
832 }
833 
834 
835 static void
fr_window_unmap(GtkWidget * widget)836 fr_window_unmap (GtkWidget *widget)
837 {
838 	FrWindow    *window = FR_WINDOW (widget);
839 	GtkSortType  order;
840 	int          column_id;
841 
842 	if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
843 						  &column_id,
844 						  &order))
845 	{
846 		g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_SORT_METHOD, column_id);
847 		g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_SORT_TYPE, order);
848 	}
849 
850 	GTK_WIDGET_CLASS (fr_window_parent_class)->unmap (widget);
851 }
852 
853 
854 static void
fr_window_class_init(FrWindowClass * klass)855 fr_window_class_init (FrWindowClass *klass)
856 {
857 	GObjectClass   *gobject_class;
858 	GtkWidgetClass *widget_class;
859 
860 	fr_window_parent_class = g_type_class_peek_parent (klass);
861 
862 	fr_window_signals[ARCHIVE_LOADED] =
863 		g_signal_new ("archive-loaded",
864 			      G_TYPE_FROM_CLASS (klass),
865 			      G_SIGNAL_RUN_LAST,
866 			      G_STRUCT_OFFSET (FrWindowClass, archive_loaded),
867 			      NULL, NULL,
868 			      fr_marshal_VOID__BOOLEAN,
869 			      G_TYPE_NONE, 1,
870 			      G_TYPE_BOOLEAN);
871 	fr_window_signals[PROGRESS] =
872 		g_signal_new ("progress",
873 			      G_TYPE_FROM_CLASS (klass),
874 			      G_SIGNAL_RUN_LAST,
875 			      G_STRUCT_OFFSET (FrWindowClass, progress),
876 			      NULL, NULL,
877 			      fr_marshal_VOID__DOUBLE_STRING,
878 			      G_TYPE_NONE, 2,
879 			      G_TYPE_DOUBLE,
880 			      G_TYPE_STRING);
881 	fr_window_signals[READY] =
882 		g_signal_new ("ready",
883 			      G_TYPE_FROM_CLASS (klass),
884 			      G_SIGNAL_RUN_LAST,
885 			      G_STRUCT_OFFSET (FrWindowClass, ready),
886 			      NULL, NULL,
887 			      fr_marshal_VOID__POINTER,
888 			      G_TYPE_NONE, 1,
889 			      G_TYPE_POINTER);
890 
891 	gobject_class = G_OBJECT_CLASS (klass);
892 	gobject_class->finalize = fr_window_finalize;
893 
894 	widget_class = GTK_WIDGET_CLASS (klass);
895 	widget_class->realize = fr_window_realize;
896 	widget_class->unrealize = fr_window_unrealize;
897 	widget_class->unmap = fr_window_unmap;
898 }
899 
900 
901 static void
fr_window_init(FrWindow * window)902 fr_window_init (FrWindow *window)
903 {
904 	window->priv = g_new0 (FrWindowPrivate, 1);
905 	window->priv->update_dropped_files = FALSE;
906 	window->priv->dnd_extract_is_running = FALSE;
907 	window->priv->dnd_extract_finished_with_error = FALSE;
908 	window->priv->filter_mode = FALSE;
909 	window->priv->use_progress_dialog = TRUE;
910 	window->priv->batch_title = NULL;
911 	window->priv->cancellable = g_cancellable_new ();
912 	window->priv->compression = FR_COMPRESSION_NORMAL;
913 	window->priv->window_group = gtk_window_group_new ();
914 	window->priv->accel_group = gtk_accel_group_new ();
915 	window->priv->populating_file_list = FALSE;
916 	window->priv->named_dialogs = g_hash_table_new (g_str_hash, g_str_equal);
917 
918 	gtk_window_group_add_window (window->priv->window_group, GTK_WINDOW (window));
919 	gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accel_group);
920 
921 	window->archive = NULL;
922 }
923 
924 
925 
926 /* -- window history -- */
927 
928 
929 #if 0
930 static void
931 fr_window_history_print (FrWindow *window)
932 {
933 	GList *list;
934 
935 	debug (DEBUG_INFO, "history:\n");
936 	for (list = window->priv->history; list; list = list->next)
937 		g_print ("\t%s %s\n",
938 			 (char*) list->data,
939 			 (list == window->priv->history_current)? "<-": "");
940 	g_print ("\n");
941 }
942 #endif
943 
944 
945 static gboolean
fr_window_dir_exists_in_archive(FrWindow * window,const char * dir_name)946 fr_window_dir_exists_in_archive (FrWindow   *window,
947 				 const char *dir_name)
948 {
949 	int dir_name_len;
950 	int i;
951 
952 	if (dir_name == NULL)
953 		return FALSE;
954 
955 	dir_name_len = strlen (dir_name);
956 	if (dir_name_len == 0)
957 		return TRUE;
958 
959 	if (strcmp (dir_name, "/") == 0)
960 		return TRUE;
961 
962 	for (i = 0; i < window->archive->files->len; i++) {
963 		FileData *fdata = g_ptr_array_index (window->archive->files, i);
964 
965 		if (strncmp (dir_name, fdata->full_path, dir_name_len) == 0) {
966 			return TRUE;
967 		}
968 		else if (fdata->dir
969 			 && (fdata->full_path[strlen (fdata->full_path) - 1] != '/')
970 			 && (strncmp (dir_name, fdata->full_path, dir_name_len - 1) == 0))
971 		{
972 			return TRUE;
973 		}
974 	}
975 
976 	return FALSE;
977 }
978 
979 
980 static void
fr_window_update_history(FrWindow * window)981 fr_window_update_history (FrWindow *window)
982 {
983 	GList *scan;
984 
985 	/* remove the paths not present in the archive */
986 
987 	for (scan = window->priv->history; scan; /* void */) {
988 		GList *next = scan->next;
989 		char  *path = scan->data;
990 
991 		if (! fr_window_dir_exists_in_archive (window, path)) {
992 			if (scan == window->priv->history_current)
993 				window->priv->history_current = NULL;
994 			window->priv->history = g_list_remove_link (window->priv->history, scan);
995 			_g_string_list_free (scan);
996 		}
997 
998 		scan = next;
999 	}
1000 
1001 	if (window->priv->history_current == NULL)
1002 		window->priv->history_current = window->priv->history;
1003 }
1004 
1005 
1006 static void
fr_window_history_add(FrWindow * window,const char * path)1007 fr_window_history_add (FrWindow   *window,
1008 		       const char *path)
1009 {
1010 	if ((window->priv->history_current == NULL) || (g_strcmp0 (path, window->priv->history_current->data) != 0)) {
1011 		GList *scan;
1012 		GList *new_current = NULL;
1013 
1014                 /* search the path in the history */
1015                 for (scan = window->priv->history_current; scan; scan = scan->next) {
1016                         char *path_in_history = scan->data;
1017 
1018                         if (g_strcmp0 (path, path_in_history) == 0) {
1019                         	new_current = scan;
1020                         	break;
1021                         }
1022                 }
1023 
1024                 if (new_current != NULL) {
1025                 	window->priv->history_current = new_current;
1026                 }
1027                 else {
1028 			/* remove all the paths after the current position */
1029 			for (scan = window->priv->history; scan && (scan != window->priv->history_current); /* void */) {
1030 				GList *next = scan->next;
1031 
1032 				window->priv->history = g_list_remove_link (window->priv->history, scan);
1033 				_g_string_list_free (scan);
1034 
1035 				scan = next;
1036 			}
1037 
1038 			window->priv->history = g_list_prepend (window->priv->history, g_strdup (path));
1039 			window->priv->history_current = window->priv->history;
1040                 }
1041 	}
1042 }
1043 
1044 
1045 static void
fr_window_history_pop(FrWindow * window)1046 fr_window_history_pop (FrWindow *window)
1047 {
1048 	GList *first;
1049 
1050 	if (window->priv->history == NULL)
1051 		return;
1052 
1053 	first = window->priv->history;
1054 	window->priv->history = g_list_remove_link (window->priv->history, first);
1055 	if (window->priv->history_current == first)
1056 		window->priv->history_current = window->priv->history;
1057 	g_free (first->data);
1058 	g_list_free (first);
1059 }
1060 
1061 
1062 /* -- activity mode -- */
1063 
1064 
1065 
1066 static void
check_whether_has_a_dir(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1067 check_whether_has_a_dir (GtkTreeModel *model,
1068 			 GtkTreePath  *path,
1069 			 GtkTreeIter  *iter,
1070 			 gpointer      data)
1071 {
1072 	gboolean *has_a_dir = data;
1073 	FileData *fdata;
1074 
1075 	gtk_tree_model_get (model, iter,
1076 			    COLUMN_FILE_DATA, &fdata,
1077 			    -1);
1078 	if (file_data_is_dir (fdata))
1079 		*has_a_dir = TRUE;
1080 }
1081 
1082 
1083 static gboolean
selection_has_a_dir(FrWindow * window)1084 selection_has_a_dir (FrWindow *window)
1085 {
1086 	GtkTreeSelection *selection;
1087 	gboolean          has_a_dir = FALSE;
1088 
1089 	if (! gtk_widget_get_realized (window->priv->list_view))
1090 		return FALSE;
1091 
1092 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
1093 	if (selection == NULL)
1094 		return FALSE;
1095 
1096 	gtk_tree_selection_selected_foreach (selection,
1097 					     check_whether_has_a_dir,
1098 					     &has_a_dir);
1099 
1100 	return has_a_dir;
1101 }
1102 
1103 
1104 static void
fr_window_update_sensitivity(FrWindow * window)1105 fr_window_update_sensitivity (FrWindow *window)
1106 {
1107 	gboolean no_archive;
1108 	gboolean ro;
1109 	gboolean file_op;
1110 	gboolean running;
1111 	gboolean can_store_many_files;
1112 	gboolean sel_not_null;
1113 	gboolean one_file_selected;
1114 	gboolean dir_selected;
1115 	int      n_selected;
1116 
1117 	if (window->priv->batch_mode)
1118 		return;
1119 
1120 	running              = window->priv->activity_ref > 0;
1121 	no_archive           = (window->archive == NULL) || ! window->priv->archive_present;
1122 	ro                   = ! no_archive && window->archive->read_only;
1123 	file_op              = ! no_archive && ! window->priv->archive_new  && ! running;
1124 	can_store_many_files = (window->archive != NULL) && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES);
1125 	n_selected           = fr_window_get_n_selected_files (window);
1126 	sel_not_null         = n_selected > 0;
1127 	one_file_selected    = n_selected == 1;
1128 	dir_selected         = selection_has_a_dir (window);
1129 
1130 #if 0
1131 	set_sensitive (window, "Add", ! no_archive && ! ro && ! running && can_store_many_files);
1132 	set_sensitive (window, "Add_Toolbar", ! no_archive && ! ro && ! running && can_store_many_files);
1133 	set_sensitive (window, "Copy", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1134 	set_sensitive (window, "Cut", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1135 	set_sensitive (window, "Delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && can_store_many_files);
1136 	set_sensitive (window, "DeselectAll", ! no_archive && sel_not_null);
1137 	set_sensitive (window, "Extract", file_op);
1138 	set_sensitive (window, "Extract_Toolbar", file_op);
1139 	set_sensitive (window, "Find", ! no_archive);
1140 	set_sensitive (window, "New", ! running);
1141 	set_sensitive (window, "Open", ! running);
1142 	set_sensitive (window, "Open_Toolbar", ! running);
1143 	set_sensitive (window, "OpenSelection", file_op && sel_not_null && ! dir_selected);
1144 	set_sensitive (window, "OpenFolder", file_op && one_file_selected && dir_selected);
1145 	set_sensitive (window, "Password", ! running && (! no_archive && window->archive->propPassword));
1146 	set_sensitive (window, "Properties", file_op);
1147 	set_sensitive (window, "Close", !running || window->priv->stoppable);
1148 	set_sensitive (window, "Reload", ! (no_archive || running));
1149 	set_sensitive (window, "Rename", ! no_archive && ! ro && ! running && can_store_many_files && one_file_selected);
1150 	set_sensitive (window, "SaveAs", ! no_archive && can_store_many_files && ! running);
1151 	set_sensitive (window, "SelectAll", ! no_archive);
1152 	set_sensitive (window, "TestArchive", ! no_archive && ! running && window->archive->propTest);
1153 	set_sensitive (window, "ViewSelection", file_op && one_file_selected && ! dir_selected);
1154 	set_sensitive (window, "ViewSelection_Toolbar", file_op && one_file_selected && ! dir_selected);
1155 #endif
1156 
1157 	if (window->priv->progress_dialog != NULL)
1158 		gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog),
1159 						   GTK_RESPONSE_OK,
1160 						   running && window->priv->stoppable);
1161 
1162 	fr_window_update_paste_command_sensitivity (window, NULL);
1163 
1164 #if 0
1165 	set_sensitive (window, "SelectAll", (window->priv->current_view_length > 0) && (window->priv->current_view_length != n_selected));
1166 	set_sensitive (window, "DeselectAll", n_selected > 0);
1167 
1168 	set_sensitive (window, "ViewSidebar", (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR));
1169 
1170 	set_sensitive (window, "ViewAllFiles", ! window->priv->filter_mode);
1171 	set_sensitive (window, "ViewAsFolder", ! window->priv->filter_mode);
1172 #endif
1173 
1174 	fr_window_enable_action (window, "add-files", ! no_archive && ! ro && ! running && can_store_many_files);
1175 	fr_window_enable_action (window, "close", ! running || window->priv->stoppable);
1176 	fr_window_enable_action (window, "delete", ! no_archive && ! ro && ! window->priv->archive_new && ! running && can_store_many_files);
1177 	fr_window_enable_action (window, "edit-copy", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1178 	fr_window_enable_action (window, "edit-cut", ! no_archive && ! ro && ! running && can_store_many_files && sel_not_null && (window->priv->list_mode != FR_WINDOW_LIST_MODE_FLAT));
1179 	fr_window_enable_action (window, "edit-password", ! running && (! no_archive && window->archive->propPassword));
1180 	fr_window_enable_action (window, "extract-files", file_op);
1181 	fr_window_enable_action (window, "find", ! no_archive);
1182 	fr_window_enable_action (window, "open-folder", file_op && one_file_selected && dir_selected);
1183 	fr_window_enable_action (window, "open-with", file_op && sel_not_null && ! dir_selected);
1184 	fr_window_enable_action (window, "rename", ! no_archive && ! ro && ! running && can_store_many_files && one_file_selected);
1185 	fr_window_enable_action (window, "save-as", ! no_archive && can_store_many_files && ! running);
1186 	fr_window_enable_action (window, "test-archive", ! no_archive && ! running && window->archive->propTest);
1187 	fr_window_enable_action (window, "view-properties", file_op);
1188 	fr_window_enable_action (window, "view-selection", file_op && one_file_selected && ! dir_selected);
1189 }
1190 
1191 
1192 static int
activity_cb(gpointer data)1193 activity_cb (gpointer data)
1194 {
1195 	FrWindow *window = data;
1196 
1197 	if ((window->priv->pd_progress_bar != NULL) && window->priv->progress_pulse)
1198 		gtk_progress_bar_pulse (GTK_PROGRESS_BAR (window->priv->pd_progress_bar));
1199 
1200 	return TRUE;
1201 }
1202 
1203 
1204 static void
_fr_window_start_activity_mode(FrWindow * window)1205 _fr_window_start_activity_mode (FrWindow *window)
1206 {
1207 	g_return_if_fail (window != NULL);
1208 
1209 	if (window->priv->activity_ref++ > 0)
1210 		return;
1211 
1212 	window->priv->activity_timeout_handle = g_timeout_add (ACTIVITY_DELAY,
1213 							       activity_cb,
1214 							       window);
1215 	fr_window_update_sensitivity (window);
1216 }
1217 
1218 
1219 static void
fr_window_pop_message(FrWindow * window)1220 fr_window_pop_message (FrWindow *window)
1221 {
1222 	if (! gtk_widget_get_mapped (GTK_WIDGET (window)))
1223 		return;
1224 
1225 	if (window->priv->progress_dialog != NULL)
1226 		gtk_label_set_text (GTK_LABEL (window->priv->pd_message), _("Operation completed"));
1227 }
1228 
1229 
1230 static GPtrArray *
fr_window_get_current_dir_list(FrWindow * window)1231 fr_window_get_current_dir_list (FrWindow *window)
1232 {
1233 	GPtrArray *files;
1234 	int        i;
1235 
1236 	files = g_ptr_array_sized_new (128);
1237 
1238 	for (i = 0; i < window->archive->files->len; i++) {
1239 		FileData *fdata = g_ptr_array_index (window->archive->files, i);
1240 
1241 		if (fdata->list_name == NULL)
1242 			continue;
1243 		g_ptr_array_add (files, fdata);
1244 	}
1245 
1246 	return files;
1247 }
1248 
1249 
1250 static void
_fr_window_stop_activity_mode(FrWindow * window)1251 _fr_window_stop_activity_mode (FrWindow *window)
1252 {
1253 	g_return_if_fail (window != NULL);
1254 
1255 	if (window->priv->activity_ref == 0)
1256 		return;
1257 
1258 	fr_window_pop_message (window);
1259 
1260 	if (--window->priv->activity_ref > 0)
1261 		return;
1262 
1263 	if (window->priv->activity_timeout_handle != 0) {
1264 		g_source_remove (window->priv->activity_timeout_handle);
1265 		window->priv->activity_timeout_handle = 0;
1266 	}
1267 
1268 	if (window->priv->progress_dialog != NULL)
1269 		gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), 0.0);
1270 
1271 	fr_window_update_sensitivity (window);
1272 }
1273 
1274 
1275 /* -- window_update_file_list -- */
1276 
1277 
1278 static guint64
get_dir_size(FrWindow * window,const char * current_dir,const char * name)1279 get_dir_size (FrWindow   *window,
1280 	      const char *current_dir,
1281 	      const char *name)
1282 {
1283 	guint64  size;
1284 	char    *dirname;
1285 	int      dirname_l;
1286 	int      i;
1287 
1288 	dirname = g_strconcat (current_dir, name, "/", NULL);
1289 	dirname_l = strlen (dirname);
1290 
1291 	size = 0;
1292 	for (i = 0; i < window->archive->files->len; i++) {
1293 		FileData *fd = g_ptr_array_index (window->archive->files, i);
1294 
1295 		if (strncmp (dirname, fd->full_path, dirname_l) == 0)
1296 			size += fd->size;
1297 	}
1298 
1299 	g_free (dirname);
1300 
1301 	return size;
1302 }
1303 
1304 
1305 static gboolean
file_data_respects_filter(FrWindow * window,GRegex * filter,FileData * fdata)1306 file_data_respects_filter (FrWindow *window,
1307 			   GRegex   *filter,
1308 			   FileData *fdata)
1309 {
1310 	if ((fdata == NULL) || (filter == NULL))
1311 		return TRUE;
1312 
1313 	if (fdata->dir || (fdata->name == NULL))
1314 		return FALSE;
1315 
1316 	return g_regex_match (filter, fdata->name, 0, NULL);
1317 }
1318 
1319 
1320 static gboolean
compute_file_list_name(FrWindow * window,GRegex * filter,FileData * fdata,const char * current_dir,int current_dir_len,GHashTable * names_hash,gboolean * different_name)1321 compute_file_list_name (FrWindow   *window,
1322 			GRegex     *filter,
1323 			FileData   *fdata,
1324 			const char *current_dir,
1325 			int         current_dir_len,
1326 			GHashTable *names_hash,
1327 			gboolean   *different_name)
1328 {
1329 	register char *scan, *end;
1330 
1331 	*different_name = FALSE;
1332 
1333 	if (! file_data_respects_filter (window, filter, fdata))
1334 		return FALSE;
1335 
1336 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
1337 		file_data_set_list_name (fdata, fdata->name);
1338 		if (fdata->dir)
1339 			fdata->dir_size = 0;
1340 		return FALSE;
1341 	}
1342 
1343 	if (strncmp (fdata->full_path, current_dir, current_dir_len) != 0) {
1344 		*different_name = TRUE;
1345 		return FALSE;
1346 	}
1347 
1348 	if (strlen (fdata->full_path) == current_dir_len)
1349 		return FALSE;
1350 
1351 	scan = fdata->full_path + current_dir_len;
1352 	end = strchr (scan, '/');
1353 	if ((end == NULL) && ! fdata->dir) { /* file */
1354 		file_data_set_list_name (fdata, scan);
1355 	}
1356 	else { /* folder */
1357 		char *dir_name;
1358 
1359 		if (end != NULL)
1360 			dir_name = g_strndup (scan, end - scan);
1361 		else
1362 			dir_name = g_strdup (scan);
1363 
1364 		/* avoid to insert duplicated folders */
1365 		if (g_hash_table_lookup (names_hash, dir_name) != NULL) {
1366 			g_free (dir_name);
1367 			return FALSE;
1368 		}
1369 		g_hash_table_insert (names_hash, dir_name, GINT_TO_POINTER (1));
1370 
1371 		if ((end != NULL) && (*(end + 1) != '\0'))
1372 			fdata->list_dir = TRUE;
1373 		file_data_set_list_name (fdata, dir_name);
1374 		fdata->dir_size = get_dir_size (window, current_dir, dir_name);
1375 	}
1376 
1377 	return TRUE;
1378 }
1379 
1380 
1381 static GRegex *
_fr_window_create_filter(FrWindow * window)1382 _fr_window_create_filter (FrWindow *window)
1383 {
1384 	GRegex     *filter;
1385 	const char *filter_str;
1386 
1387 	filter = NULL;
1388 	filter_str = gtk_entry_get_text (GTK_ENTRY (window->priv->filter_entry));
1389 	if ((filter_str != NULL) && (*filter_str != '\0')) {
1390 		char *escaped;
1391 		char *pattern;
1392 
1393 		escaped = g_regex_escape_string (filter_str, -1);
1394 		pattern = g_strdup_printf (".*%s.*", escaped);
1395 		filter = g_regex_new (pattern, G_REGEX_CASELESS | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY, NULL);
1396 
1397 		g_free (pattern);
1398 		g_free (escaped);
1399 	}
1400 
1401 	return filter;
1402 }
1403 
1404 
1405 static void
fr_window_compute_list_names(FrWindow * window,GPtrArray * files)1406 fr_window_compute_list_names (FrWindow  *window,
1407 			      GPtrArray *files)
1408 {
1409 	const char *current_dir;
1410 	int         current_dir_len;
1411 	GHashTable *names_hash;
1412 	GRegex     *filter;
1413 	int         i;
1414 	gboolean    visible_list_started = FALSE;
1415 	gboolean    visible_list_completed = FALSE;
1416 	gboolean    different_name;
1417 
1418 	current_dir = fr_window_get_current_location (window);
1419 	current_dir_len = strlen (current_dir);
1420 	names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1421 
1422 	filter = _fr_window_create_filter (window);
1423 	for (i = 0; i < files->len; i++) {
1424 		FileData *fdata = g_ptr_array_index (files, i);
1425 
1426 		file_data_set_list_name (fdata, NULL);
1427 		fdata->list_dir = FALSE;
1428 
1429 		/* the files array is sorted by path, when the visible list
1430 		 * is started and we find a path that doesn't match the
1431 		 * current_dir path, the following files can't match
1432 		 * the current_dir path. */
1433 
1434 		if (visible_list_completed)
1435 			continue;
1436 
1437 		if (compute_file_list_name (window, filter, fdata, current_dir, current_dir_len, names_hash, &different_name)) {
1438 			visible_list_started = TRUE;
1439 		}
1440 		else if (visible_list_started && different_name)
1441 			visible_list_completed = TRUE;
1442 	}
1443 
1444 	if (filter != NULL)
1445 		g_regex_unref (filter);
1446 	g_hash_table_destroy (names_hash);
1447 }
1448 
1449 
1450 static char *
get_parent_dir(const char * current_dir)1451 get_parent_dir (const char *current_dir)
1452 {
1453 	char *dir;
1454 	char *new_dir;
1455 	char *retval;
1456 
1457 	if (current_dir == NULL)
1458 		return NULL;
1459 	if (strcmp (current_dir, "/") == 0)
1460 		return g_strdup ("/");
1461 
1462 	dir = g_strdup (current_dir);
1463 	dir[strlen (dir) - 1] = 0;
1464 	new_dir = _g_path_remove_level (dir);
1465 	g_free (dir);
1466 
1467 	if (new_dir[strlen (new_dir) - 1] == '/')
1468 		retval = new_dir;
1469 	else {
1470 		retval = g_strconcat (new_dir, "/", NULL);
1471 		g_free (new_dir);
1472 	}
1473 
1474 	return retval;
1475 }
1476 
1477 
1478 static GdkPixbuf *
get_mime_type_icon(FrWindow * window,const char * mime_type)1479 get_mime_type_icon (FrWindow   *window,
1480 		    const char *mime_type)
1481 {
1482 	GIcon     *icon;
1483 	GdkPixbuf *pixbuf;
1484 
1485 	icon = g_content_type_get_icon (mime_type);
1486 	pixbuf = gth_icon_cache_get_pixbuf (window->priv->tree_icon_cache, icon);
1487 
1488 	g_object_unref (icon);
1489 
1490 	return pixbuf;
1491 }
1492 
1493 
1494 static GdkPixbuf *
get_icon(FrWindow * window,FileData * fdata)1495 get_icon (FrWindow  *window,
1496 	  FileData  *fdata)
1497 {
1498 	GIcon     *icon = NULL;
1499 	GdkPixbuf *pixbuf = NULL;
1500 
1501 	if (fdata->link != NULL)
1502 		icon = g_themed_icon_new ("emblem-symbolic-link");
1503 	else {
1504 		const char *content_type;
1505 
1506 		if (file_data_is_dir (fdata))
1507 			content_type = MIME_TYPE_DIRECTORY;
1508 		else
1509 			content_type = fdata->content_type;
1510 		icon = g_content_type_get_icon (content_type);
1511 	}
1512 
1513 	pixbuf = gth_icon_cache_get_pixbuf (window->priv->list_icon_cache, icon);
1514 	g_object_unref (icon);
1515 
1516 	return pixbuf;
1517 }
1518 
1519 
1520 static GdkPixbuf *
get_emblem(FrWindow * window,FileData * fdata)1521 get_emblem (FrWindow *window,
1522 	    FileData *fdata)
1523 {
1524 	const char *emblem_name;
1525 	GIcon      *icon;
1526 	GdkPixbuf  *pixbuf;
1527 
1528 	emblem_name = NULL;
1529 	if (fdata->encrypted)
1530 		emblem_name = "emblem-readonly";
1531 
1532 	if (emblem_name == NULL)
1533 		return NULL;
1534 
1535 	icon = g_themed_icon_new (emblem_name);
1536 	pixbuf = gth_icon_cache_get_pixbuf (window->priv->list_icon_cache, icon);
1537 	g_object_unref (icon);
1538 
1539 	return pixbuf;
1540 }
1541 
1542 
1543 static void
add_selected_from_list_view(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1544 add_selected_from_list_view (GtkTreeModel *model,
1545 			     GtkTreePath  *path,
1546 			     GtkTreeIter  *iter,
1547 			     gpointer      data)
1548 {
1549 	GList    **list = data;
1550 	FileData  *fdata;
1551 
1552 	gtk_tree_model_get (model, iter,
1553 			    COLUMN_FILE_DATA, &fdata,
1554 			    -1);
1555 	*list = g_list_prepend (*list, fdata);
1556 }
1557 
1558 
1559 static void
add_selected_from_tree_view(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1560 add_selected_from_tree_view (GtkTreeModel *model,
1561 			     GtkTreePath  *path,
1562 			     GtkTreeIter  *iter,
1563 			     gpointer      data)
1564 {
1565 	GList **list = data;
1566 	char   *dir_path;
1567 
1568 	gtk_tree_model_get (model, iter,
1569 			    TREE_COLUMN_PATH, &dir_path,
1570 			    -1);
1571 	*list = g_list_prepend (*list, dir_path);
1572 }
1573 
1574 
1575 static void
fr_window_populate_file_list(FrWindow * window,GPtrArray * files)1576 fr_window_populate_file_list (FrWindow  *window,
1577 			      GPtrArray *files)
1578 {
1579 	int         sort_column_id;
1580 	GtkSortType order;
1581 	int         i;
1582 
1583 	if (! gtk_widget_get_realized (GTK_WIDGET (window))) {
1584 		_fr_window_stop_activity_mode (window);
1585 		return;
1586 	}
1587 
1588 	window->priv->populating_file_list = TRUE;
1589 	gtk_list_store_clear (window->priv->list_store);
1590 
1591 	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
1592 					      &sort_column_id,
1593 					      &order);
1594 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
1595 	 				      GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
1596 	 				      0);
1597 
1598 	for (i = 0; i < files->len; i++) {
1599 		FileData    *fdata = g_ptr_array_index (files, i);
1600 		GtkTreeIter  iter;
1601 		GdkPixbuf   *icon, *emblem;
1602 		char        *utf8_name;
1603 
1604 		if (fdata->list_name == NULL)
1605 			continue;
1606 
1607 		gtk_list_store_append (window->priv->list_store, &iter);
1608 
1609 		icon = get_icon (window, fdata);
1610 		emblem = get_emblem (window, fdata);
1611 		utf8_name = g_filename_display_name (fdata->list_name);
1612 
1613 		if (file_data_is_dir (fdata)) {
1614 			char *utf8_path;
1615 			char *tmp;
1616 			char *s_size;
1617 			char *s_time;
1618 
1619 			if (fdata->list_dir)
1620 				tmp = _g_path_remove_ending_separator (fr_window_get_current_location (window));
1621 
1622 			else
1623 				tmp = _g_path_remove_level (fdata->path);
1624 			utf8_path = g_filename_display_name (tmp);
1625 			g_free (tmp);
1626 
1627 			s_size = g_format_size (fdata->dir_size);
1628 
1629 			if (fdata->list_dir)
1630 				s_time = g_strdup ("");
1631 			else
1632 				s_time = _g_time_to_string (fdata->modified);
1633 
1634 			gtk_list_store_set (window->priv->list_store, &iter,
1635 					    COLUMN_FILE_DATA, fdata,
1636 					    COLUMN_ICON, icon,
1637 					    COLUMN_NAME, utf8_name,
1638 					    COLUMN_EMBLEM, emblem,
1639 					    COLUMN_TYPE, _("Folder"),
1640 					    COLUMN_SIZE, s_size,
1641 					    COLUMN_TIME, s_time,
1642 					    COLUMN_PATH, utf8_path,
1643 					    -1);
1644 			g_free (utf8_path);
1645 			g_free (s_size);
1646 			g_free (s_time);
1647 		}
1648 		else {
1649 			char *utf8_path;
1650 			char *s_size;
1651 			char *s_time;
1652 			char *desc;
1653 
1654 			utf8_path = g_filename_display_name (fdata->path);
1655 
1656 			s_size = g_format_size (fdata->size);
1657 			s_time = _g_time_to_string (fdata->modified);
1658 			desc = g_content_type_get_description (fdata->content_type);
1659 
1660 			gtk_list_store_set (window->priv->list_store, &iter,
1661 					    COLUMN_FILE_DATA, fdata,
1662 					    COLUMN_ICON, icon,
1663 					    COLUMN_NAME, utf8_name,
1664 					    COLUMN_EMBLEM, emblem,
1665 					    COLUMN_TYPE, desc,
1666 					    COLUMN_SIZE, s_size,
1667 					    COLUMN_TIME, s_time,
1668 					    COLUMN_PATH, utf8_path,
1669 					    -1);
1670 			g_free (utf8_path);
1671 			g_free (s_size);
1672 			g_free (s_time);
1673 			g_free (desc);
1674 		}
1675 
1676 		g_free (utf8_name);
1677 		_g_object_unref (icon);
1678 		_g_object_unref (emblem);
1679 	}
1680 
1681 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (window->priv->list_store),
1682 					      sort_column_id,
1683 					      order);
1684 
1685 	window->priv->populating_file_list = FALSE;
1686 
1687 	_fr_window_stop_activity_mode (window);
1688 }
1689 
1690 
1691 static int
path_compare(gconstpointer a,gconstpointer b)1692 path_compare (gconstpointer a,
1693 	      gconstpointer b)
1694 {
1695 	char *path_a = *((char**) a);
1696 	char *path_b = *((char**) b);
1697 
1698 	return strcmp (path_a, path_b);
1699 }
1700 
1701 
1702 static gboolean
get_tree_iter_from_path(FrWindow * window,const char * path,GtkTreeIter * parent,GtkTreeIter * iter)1703 get_tree_iter_from_path (FrWindow    *window,
1704 			 const char  *path,
1705 			 GtkTreeIter *parent,
1706 			 GtkTreeIter *iter)
1707 {
1708 	gboolean    result = FALSE;
1709 
1710 	if (! gtk_tree_model_iter_children (GTK_TREE_MODEL (window->priv->tree_store), iter, parent))
1711 		return FALSE;
1712 
1713 	do {
1714 		GtkTreeIter  tmp;
1715 		char        *iter_path;
1716 
1717 		if (get_tree_iter_from_path (window, path, iter, &tmp)) {
1718 			*iter = tmp;
1719 			return TRUE;
1720 		}
1721 
1722 		gtk_tree_model_get (GTK_TREE_MODEL (window->priv->tree_store),
1723 				    iter,
1724 				    TREE_COLUMN_PATH, &iter_path,
1725 				    -1);
1726 
1727 		if ((iter_path != NULL) && (strcmp (path, iter_path) == 0)) {
1728 			result = TRUE;
1729 			g_free (iter_path);
1730 			break;
1731 		}
1732 		g_free (iter_path);
1733 	}
1734 	while (gtk_tree_model_iter_next (GTK_TREE_MODEL (window->priv->tree_store), iter));
1735 
1736 	return result;
1737 }
1738 
1739 
1740 static void
fr_window_deactivate_filter(FrWindow * window)1741 fr_window_deactivate_filter (FrWindow *window)
1742 {
1743 	fr_window_change_action_state (window, "find", FALSE);
1744 }
1745 
1746 
1747 static void
fr_window_update_current_location(FrWindow * window)1748 fr_window_update_current_location (FrWindow *window)
1749 {
1750 	const char *current_dir = fr_window_get_current_location (window);
1751 	char       *path;
1752 	GtkTreeIter iter;
1753 
1754 	gtk_widget_set_visible (window->priv->location_bar, window->priv->archive_present && (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR));
1755 
1756 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)
1757 		return;
1758 
1759 	gtk_entry_set_text (GTK_ENTRY (window->priv->location_entry), window->priv->archive_present? current_dir: "");
1760 
1761 	fr_window_enable_action (window, "go-back", window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->next != NULL));
1762 	fr_window_enable_action (window, "go-forward", window->priv->archive_present && (current_dir != NULL) && (window->priv->history_current != NULL) && (window->priv->history_current->prev != NULL));
1763 	fr_window_enable_action (window, "go-home", window->priv->archive_present);
1764 
1765 	gtk_widget_set_sensitive (window->priv->location_entry, window->priv->archive_present);
1766 	gtk_widget_set_sensitive (window->priv->location_label, window->priv->archive_present);
1767 	gtk_widget_set_sensitive (window->priv->filter_entry, window->priv->archive_present);
1768 
1769 	fr_window_deactivate_filter (window);
1770 
1771 #if 0
1772 	fr_window_history_print (window);
1773 #endif
1774 
1775 	path = _g_path_remove_ending_separator (current_dir);
1776 	if (get_tree_iter_from_path (window, path, NULL, &iter)) {
1777 		GtkTreeSelection *selection;
1778 		GtkTreePath      *t_path;
1779 
1780 		t_path = gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &iter);
1781 		gtk_tree_view_expand_to_path (GTK_TREE_VIEW (window->priv->tree_view), t_path);
1782 		gtk_tree_path_free (t_path);
1783 
1784 		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
1785 		gtk_tree_selection_select_iter (selection, &iter);
1786 	}
1787 	g_free (path);
1788 }
1789 
1790 
1791 static void
fr_window_update_dir_tree(FrWindow * window)1792 fr_window_update_dir_tree (FrWindow *window)
1793 {
1794 	GPtrArray  *dirs;
1795 	GRegex     *filter;
1796 	GHashTable *dir_cache;
1797 	int         i;
1798 	GdkPixbuf  *icon;
1799 
1800 	if (! gtk_widget_get_realized (GTK_WIDGET (window)))
1801 		return;
1802 
1803 	gtk_tree_store_clear (window->priv->tree_store);
1804 
1805 	if (! window->priv->view_sidebar
1806 	    || ! window->priv->archive_present
1807 	    || (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT))
1808 	{
1809 		gtk_widget_set_sensitive (window->priv->tree_view, FALSE);
1810 		gtk_widget_hide (window->priv->sidepane);
1811 		return;
1812 	}
1813 	else {
1814 		gtk_widget_set_sensitive (window->priv->tree_view, TRUE);
1815 		if (! gtk_widget_get_visible (window->priv->sidepane))
1816 			gtk_widget_show_all (window->priv->sidepane);
1817 	}
1818 
1819 	if (gtk_widget_get_realized (window->priv->tree_view))
1820 		gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->tree_view), 0, 0);
1821 
1822 	/**/
1823 
1824 	dirs = g_ptr_array_sized_new (128);
1825 
1826 	filter = _fr_window_create_filter (window);
1827 	dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
1828 	for (i = 0; i < window->archive->files->len; i++) {
1829 		FileData *fdata = g_ptr_array_index (window->archive->files, i);
1830 		char     *dir;
1831 
1832 		if (! file_data_respects_filter (window, filter, fdata))
1833 			continue;
1834 
1835 		if (fdata->dir)
1836 			dir = _g_path_remove_ending_separator (fdata->full_path);
1837 		else
1838 			dir = _g_path_remove_level (fdata->full_path);
1839 
1840 		while ((dir != NULL) && (strcmp (dir, "/") != 0)) {
1841 			char *new_dir;
1842 
1843 			if (g_hash_table_lookup (dir_cache, dir) != NULL)
1844 				break;
1845 
1846 			new_dir = dir;
1847 			g_ptr_array_add (dirs, new_dir);
1848 			g_hash_table_replace (dir_cache, new_dir, "1");
1849 
1850 			dir = _g_path_remove_level (new_dir);
1851 		}
1852 
1853 		g_free (dir);
1854 	}
1855 	g_hash_table_destroy (dir_cache);
1856 	if (filter != NULL)
1857 		g_regex_unref (filter);
1858 
1859 	g_ptr_array_sort (dirs, path_compare);
1860 	dir_cache = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) gtk_tree_path_free);
1861 
1862 	/**/
1863 
1864 	icon = get_mime_type_icon (window, MIME_TYPE_ARCHIVE);
1865 	{
1866 		GtkTreeIter  node;
1867 		char        *name;
1868 
1869 		name = _g_file_get_display_basename (fr_archive_get_file (window->archive));
1870 
1871 		gtk_tree_store_append (window->priv->tree_store, &node, NULL);
1872 		gtk_tree_store_set (window->priv->tree_store, &node,
1873 				    TREE_COLUMN_ICON, icon,
1874 				    TREE_COLUMN_NAME, name,
1875 				    TREE_COLUMN_PATH, "/",
1876 				    TREE_COLUMN_WEIGHT, PANGO_WEIGHT_BOLD,
1877 				    -1);
1878 		g_hash_table_replace (dir_cache, "/", gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &node));
1879 
1880 		g_free (name);
1881 	}
1882 	g_object_unref (icon);
1883 
1884 	/**/
1885 
1886 	icon = get_mime_type_icon (window, MIME_TYPE_DIRECTORY);
1887 	for (i = 0; i < dirs->len; i++) {
1888 		char        *dir = g_ptr_array_index (dirs, i);
1889 		char        *parent_dir;
1890 		GtkTreePath *parent_path;
1891 		GtkTreeIter  parent;
1892 		GtkTreeIter  node;
1893 
1894 		parent_dir = _g_path_remove_level (dir);
1895 		if (parent_dir == NULL)
1896 			continue;
1897 
1898 		parent_path = g_hash_table_lookup (dir_cache, parent_dir);
1899 		gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->tree_store),
1900 					 &parent,
1901 					 parent_path);
1902 		gtk_tree_store_append (window->priv->tree_store, &node, &parent);
1903 		gtk_tree_store_set (window->priv->tree_store, &node,
1904 				    TREE_COLUMN_ICON, icon,
1905 				    TREE_COLUMN_NAME, _g_path_get_basename (dir),
1906 				    TREE_COLUMN_PATH, dir,
1907 				    TREE_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
1908 				    -1);
1909 		g_hash_table_replace (dir_cache, dir, gtk_tree_model_get_path (GTK_TREE_MODEL (window->priv->tree_store), &node));
1910 
1911 		g_free (parent_dir);
1912 	}
1913 	g_hash_table_destroy (dir_cache);
1914 	if (icon != NULL)
1915 		g_object_unref (icon);
1916 
1917 	g_ptr_array_free (dirs, TRUE);
1918 
1919 	fr_window_update_current_location (window);
1920 }
1921 
1922 
1923 static void
fr_window_update_file_list(FrWindow * window,gboolean update_view)1924 fr_window_update_file_list (FrWindow *window,
1925 			    gboolean  update_view)
1926 {
1927 	GPtrArray  *files;
1928 	gboolean    free_files = FALSE;
1929 
1930 	if (! gtk_widget_get_realized (GTK_WIDGET (window)))
1931 		return;
1932 
1933 	if (gtk_widget_get_realized (window->priv->list_view))
1934 		gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (window->priv->list_view), 0, 0);
1935 
1936 	if (! window->priv->archive_present || window->priv->archive_new) {
1937 		if (update_view)
1938 			gtk_list_store_clear (window->priv->list_store);
1939 
1940 		window->priv->current_view_length = 0;
1941 
1942 		if (window->priv->archive_new) {
1943 			gtk_widget_set_sensitive (window->priv->list_view, TRUE);
1944 			gtk_widget_show_all (gtk_widget_get_parent (window->priv->list_view));
1945 		}
1946 		else {
1947 			gtk_widget_set_sensitive (window->priv->list_view, FALSE);
1948 			gtk_widget_hide (gtk_widget_get_parent (window->priv->list_view));
1949 		}
1950 
1951 		return;
1952 	}
1953 	else {
1954 		gtk_widget_set_sensitive (window->priv->list_view, TRUE);
1955 		gtk_widget_show_all (gtk_widget_get_parent (window->priv->list_view));
1956 	}
1957 
1958 	if (window->priv->give_focus_to_the_list) {
1959 		gtk_widget_grab_focus (window->priv->list_view);
1960 		window->priv->give_focus_to_the_list = FALSE;
1961 	}
1962 
1963 	/**/
1964 
1965 	_fr_window_start_activity_mode (window);
1966 
1967 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
1968 		fr_window_compute_list_names (window, window->archive->files);
1969 		files = window->archive->files;
1970 		free_files = FALSE;
1971 	}
1972 	else {
1973 		char *current_dir = g_strdup (fr_window_get_current_location (window));
1974 
1975 		while (! fr_window_dir_exists_in_archive (window, current_dir)) {
1976 			char *tmp;
1977 
1978 			fr_window_history_pop (window);
1979 
1980 			tmp = get_parent_dir (current_dir);
1981 			g_free (current_dir);
1982 			current_dir = tmp;
1983 
1984 			fr_window_history_add (window, current_dir);
1985 		}
1986 		g_free (current_dir);
1987 
1988 		fr_window_compute_list_names (window, window->archive->files);
1989 		files = fr_window_get_current_dir_list (window);
1990 		free_files = TRUE;
1991 	}
1992 
1993 	if (files != NULL)
1994 		window->priv->current_view_length = files->len;
1995 	else
1996 		window->priv->current_view_length = 0;
1997 
1998 	if (update_view)
1999 		fr_window_populate_file_list (window, files);
2000 
2001 	if (free_files)
2002 		g_ptr_array_free (files, TRUE);
2003 }
2004 
2005 
2006 static void
fr_window_set_title(FrWindow * window,const char * title)2007 fr_window_set_title (FrWindow   *window,
2008 		     const char *title)
2009 {
2010 	gtk_window_set_title (GTK_WINDOW (window), title);
2011 	gtk_header_bar_set_title (GTK_HEADER_BAR (window->priv->headerbar), title);
2012 }
2013 
2014 
2015 static void
fr_window_update_title(FrWindow * window)2016 fr_window_update_title (FrWindow *window)
2017 {
2018 	char *title;
2019 	char *name;
2020 
2021 	if (! window->priv->archive_present) {
2022 		fr_window_set_title (window, _("Archive Manager"));
2023 		return;
2024 	}
2025 
2026 	name = _g_file_get_display_basename (fr_window_get_archive_file (window));
2027 	title = g_strdup_printf ("%s %s",
2028 				 name,
2029 				 window->archive->read_only ? _("[read only]") : "");
2030 	fr_window_set_title (window, title);
2031 
2032 	g_free (title);
2033 	g_free (name);
2034 }
2035 
2036 
2037 static gboolean
location_entry_key_press_event_cb(GtkWidget * widget,GdkEventKey * event,FrWindow * window)2038 location_entry_key_press_event_cb (GtkWidget   *widget,
2039 				   GdkEventKey *event,
2040 				   FrWindow    *window)
2041 {
2042 	if ((event->keyval == GDK_KEY_Return)
2043 	    || (event->keyval == GDK_KEY_KP_Enter)
2044 	    || (event->keyval == GDK_KEY_ISO_Enter))
2045 	{
2046 		fr_window_go_to_location (window, gtk_entry_get_text (GTK_ENTRY (window->priv->location_entry)), FALSE);
2047 	}
2048 
2049 	return FALSE;
2050 }
2051 
2052 
2053 static void
_fr_window_close_after_notification(FrWindow * window)2054 _fr_window_close_after_notification (FrWindow *window)
2055 {
2056 	fr_window_set_current_action (window, FR_BATCH_ACTION_QUIT, NULL, NULL);
2057 	fr_window_restart_current_action (window);
2058 }
2059 
2060 
2061 static gboolean
real_close_progress_dialog(gpointer data)2062 real_close_progress_dialog (gpointer data)
2063 {
2064 	FrWindow *window = data;
2065 
2066 	if (window->priv->hide_progress_timeout != 0) {
2067 		g_source_remove (window->priv->hide_progress_timeout);
2068 		window->priv->hide_progress_timeout = 0;
2069 	}
2070 
2071 	if (window->priv->progress_dialog != NULL)
2072 		gtk_widget_hide (window->priv->progress_dialog);
2073 
2074 	return FALSE;
2075 }
2076 
2077 
2078 static void
close_progress_dialog(FrWindow * window,gboolean close_now)2079 close_progress_dialog (FrWindow *window,
2080 		       gboolean  close_now)
2081 {
2082 	if (window->priv->progress_timeout != 0) {
2083 		g_source_remove (window->priv->progress_timeout);
2084 		window->priv->progress_timeout = 0;
2085 	}
2086 
2087 	if (window->priv->progress_dialog == NULL)
2088 		return;
2089 
2090 	if (close_now) {
2091 		if (window->priv->hide_progress_timeout != 0) {
2092 			g_source_remove (window->priv->hide_progress_timeout);
2093 			window->priv->hide_progress_timeout = 0;
2094 		}
2095 		real_close_progress_dialog (window);
2096 	}
2097 	else {
2098 		if (window->priv->hide_progress_timeout != 0)
2099 			return;
2100 		window->priv->hide_progress_timeout = g_timeout_add (HIDE_PROGRESS_TIMEOUT_MSECS,
2101 								     real_close_progress_dialog,
2102 								     window);
2103 	}
2104 }
2105 
2106 
2107 static gboolean
progress_dialog_delete_event(GtkWidget * caller,GdkEvent * event,FrWindow * window)2108 progress_dialog_delete_event (GtkWidget *caller,
2109 			      GdkEvent  *event,
2110 			      FrWindow  *window)
2111 {
2112 	if (window->priv->stoppable) {
2113 		fr_window_stop (window);
2114 		close_progress_dialog (window, TRUE);
2115 	}
2116 
2117 	return TRUE;
2118 }
2119 
2120 
2121 /* -- open_folder -- */
2122 
2123 
2124 typedef struct {
2125 	GtkWindow *window;
2126 	GFile     *folder;
2127 } OpenFolderData;
2128 
2129 
2130 static OpenFolderData *
open_folder_data_new(GtkWindow * window,GFile * folder)2131 open_folder_data_new (GtkWindow *window,
2132 		      GFile     *folder)
2133 {
2134 	OpenFolderData *data;
2135 
2136 	data = g_new (OpenFolderData, 1);
2137 	data->window = g_object_ref (window);
2138 	data->folder = g_object_ref (folder);
2139 
2140 	return data;
2141 }
2142 
2143 
2144 static void
open_folder_data_free(OpenFolderData * data)2145 open_folder_data_free (OpenFolderData *data)
2146 {
2147 	_g_object_unref (data->window);
2148 	_g_object_unref (data->folder);
2149 	g_free (data);
2150 }
2151 
2152 
2153 static void
show_folder(GtkWindow * parent_window,GFile * folder)2154 show_folder (GtkWindow *parent_window,
2155 	     GFile     *folder)
2156 {
2157 	GError *error = NULL;
2158 	char   *uri;
2159 
2160 	uri = g_file_get_uri (folder);
2161 	if (! gtk_show_uri_on_window (parent_window, uri, GDK_CURRENT_TIME, &error))
2162 	{
2163 		GtkWidget *d;
2164 		char      *utf8_name;
2165 		char      *message;
2166 
2167 		utf8_name = _g_file_get_display_basename (folder);
2168 		message = g_strdup_printf (_("Could not display the folder “%s”"), utf8_name);
2169 		g_free (utf8_name);
2170 
2171 		d = _gtk_error_dialog_new (parent_window,
2172 					   GTK_DIALOG_MODAL,
2173 					   NULL,
2174 					   message,
2175 					   "%s",
2176 					   error->message);
2177 		gtk_dialog_run (GTK_DIALOG (d));
2178 		gtk_widget_destroy (d);
2179 
2180 		g_free (message);
2181 		g_clear_error (&error);
2182 	}
2183 
2184 	g_free (uri);
2185 }
2186 
2187 
2188 static void
file_manager_show_items_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2189 file_manager_show_items_cb (GObject      *source_object,
2190 			    GAsyncResult *res,
2191 			    gpointer      user_data)
2192 {
2193 	OpenFolderData *data = user_data;
2194 	GDBusProxy     *proxy;
2195 	GVariant       *values;
2196 	GError         *error = NULL;
2197 
2198 	proxy = G_DBUS_PROXY (source_object);
2199 	values = g_dbus_proxy_call_finish (proxy, res, &error);
2200 	if (values == NULL) {
2201 		show_folder (data->window, data->folder);
2202 		g_clear_error (&error);
2203 	}
2204 
2205 	if (values != NULL)
2206 		g_variant_unref (values);
2207 	g_object_unref (proxy);
2208 	open_folder_data_free (data);
2209 }
2210 
2211 
2212 static void
open_folder(GtkWindow * parent_window,GFile * folder,GList * files)2213 open_folder (GtkWindow    *parent_window,
2214 	     GFile        *folder,
2215 	     GList        *files)
2216 {
2217 	GDBusConnection *connection;
2218 	GError          *error = NULL;
2219 
2220 	if (folder == NULL)
2221 		return;
2222 
2223 	/* only use ShowItems if its a single file to avoid Nautilus to open
2224 	 * multiple windows */
2225 
2226 	if ((files == NULL) || (files->next != NULL)) {
2227 		show_folder (parent_window, folder);
2228 		return;
2229 	}
2230 
2231 	connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
2232 	if (connection != NULL) {
2233 		GDBusProxy *proxy;
2234 
2235 		proxy = g_dbus_proxy_new_sync (connection,
2236 					       G_DBUS_PROXY_FLAGS_NONE,
2237 					       NULL,
2238 					       "org.freedesktop.FileManager1",
2239 					       "/org/freedesktop/FileManager1",
2240 					       "org.freedesktop.FileManager1",
2241 					       NULL,
2242 					       &error);
2243 
2244 		if (proxy != NULL) {
2245 			static int   sequence = 0;
2246 			char       **uris;
2247 			char        *startup_id;
2248 
2249 			uris = g_new (char *, 2);
2250 			uris[0] = g_file_get_uri ((GFile *) files->data);
2251 			uris[1] = NULL;
2252 
2253 			startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
2254 						      g_get_prgname (),
2255 						      (unsigned long) getpid (),
2256 						      g_get_host_name (),
2257 						      "org.freedesktop.FileManager1",
2258 						      sequence++,
2259 						      (unsigned long) g_get_real_time ());
2260 
2261 			g_dbus_proxy_call (proxy,
2262 					   "ShowItems",
2263 					   g_variant_new ("(^ass)", uris, startup_id),
2264 					   G_DBUS_CALL_FLAGS_NONE,
2265 					   G_MAXINT,
2266 					   NULL,
2267 					   file_manager_show_items_cb,
2268 					   open_folder_data_new (parent_window, folder));
2269 
2270 			g_free (startup_id);
2271 			g_strfreev (uris);
2272 
2273 			return;
2274 		}
2275 	}
2276 
2277 	show_folder (parent_window, folder);
2278 }
2279 
2280 
2281 static void
fr_window_view_extraction_destination_folder(FrWindow * window)2282 fr_window_view_extraction_destination_folder (FrWindow *window)
2283 {
2284 	open_folder (GTK_WINDOW (window), window->priv->last_extraction_destination, window->priv->last_extraction_files_first_level);
2285 }
2286 
2287 
2288 static void
progress_dialog_response(GtkDialog * dialog,int response_id,FrWindow * window)2289 progress_dialog_response (GtkDialog *dialog,
2290 			  int        response_id,
2291 			  FrWindow  *window)
2292 {
2293 	GtkWidget *new_window;
2294 	GFile     *saved_file;
2295 
2296 	saved_file = window->priv->saving_file;
2297 	window->priv->saving_file = NULL;
2298 
2299 	switch (response_id) {
2300 	case GTK_RESPONSE_CANCEL:
2301 		if (window->priv->stoppable) {
2302 			fr_window_stop (window);
2303 			close_progress_dialog (window, TRUE);
2304 		}
2305 		break;
2306 	case GTK_RESPONSE_CLOSE:
2307 		close_progress_dialog (window, TRUE);
2308 		break;
2309 	case DIALOG_RESPONSE_OPEN_ARCHIVE:
2310 		new_window = fr_window_new ();
2311 		gtk_widget_show (new_window);
2312 		fr_window_archive_open (FR_WINDOW (new_window), saved_file, GTK_WINDOW (new_window));
2313 		close_progress_dialog (window, TRUE);
2314 		break;
2315 	case DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER:
2316 		fr_window_view_extraction_destination_folder (window);
2317 		close_progress_dialog (window, TRUE);
2318 		break;
2319 	default:
2320 		break;
2321 	}
2322 
2323 	_g_object_unref (saved_file);
2324 }
2325 
2326 
2327 static char *
get_action_description(FrWindow * window,FrAction action,GFile * file)2328 get_action_description (FrWindow *window,
2329 			FrAction  action,
2330 			GFile    *file)
2331 {
2332 	char *basename;
2333 	char *message;
2334 
2335 	basename = _g_file_get_display_basename (file);
2336 
2337 	message = NULL;
2338 	switch (action) {
2339 	case FR_ACTION_CREATING_NEW_ARCHIVE:
2340 		/* Translators: %s is a filename */
2341 		message = g_strdup_printf (_("Creating “%s”"), basename);
2342 		break;
2343 	case FR_ACTION_LOADING_ARCHIVE:
2344 		/* Translators: %s is a filename */
2345 		message = g_strdup_printf (_("Loading “%s”"), basename);
2346 		break;
2347 	case FR_ACTION_LISTING_CONTENT:
2348 		/* Translators: %s is a filename */
2349 		message = g_strdup_printf (_("Reading “%s”"), basename);
2350 		break;
2351 	case FR_ACTION_DELETING_FILES:
2352 		/* Translators: %s is a filename */
2353 		message = g_strdup_printf (_("Deleting the files from “%s”"), basename);
2354 		break;
2355 	case FR_ACTION_TESTING_ARCHIVE:
2356 		/* Translators: %s is a filename */
2357 		message = g_strdup_printf (_("Testing “%s”"), basename);
2358 		break;
2359 	case FR_ACTION_GETTING_FILE_LIST:
2360 		message = g_strdup (_("Getting the file list"));
2361 		break;
2362 	case FR_ACTION_COPYING_FILES_FROM_REMOTE:
2363 		/* Translators: %s is a filename */
2364 		message = g_strdup_printf (_("Copying the files to add to “%s”"), basename);
2365 		break;
2366 	case FR_ACTION_ADDING_FILES:
2367 		/* Translators: %s is a filename */
2368 		message = g_strdup_printf (_("Adding the files to “%s”"), basename);
2369 		break;
2370 	case FR_ACTION_EXTRACTING_FILES:
2371 		/* Translators: %s is a filename */
2372 		message = g_strdup_printf (_("Extracting the files from “%s”"), basename);
2373 		break;
2374 	case FR_ACTION_COPYING_FILES_TO_REMOTE:
2375 		message = g_strdup (_("Copying the extracted files to the destination"));
2376 		break;
2377 	case FR_ACTION_CREATING_ARCHIVE:
2378 		/* Translators: %s is a filename */
2379 		message = g_strdup_printf (_("Creating “%s”"), basename);
2380 		break;
2381 	case FR_ACTION_SAVING_REMOTE_ARCHIVE:
2382 	case FR_ACTION_ENCRYPTING_ARCHIVE:
2383 		/* Translators: %s is a filename */
2384 		message = g_strdup_printf (_("Saving “%s”"), basename);
2385 		break;
2386 	case FR_ACTION_PASTING_FILES:
2387 		message = g_strdup (window->priv->custom_action_message);
2388 		break;
2389 	case FR_ACTION_RENAMING_FILES:
2390 		/* Translators: %s is a filename */
2391 		message = g_strdup_printf (_("Renaming the files in “%s”"), basename);
2392 		break;
2393 	case FR_ACTION_UPDATING_FILES:
2394 		/* Translators: %s is a filename */
2395 		message = g_strdup_printf (_("Updating the files in “%s”"), basename);
2396 		break;
2397 	case FR_ACTION_NONE:
2398 		break;
2399 	}
2400 
2401 	g_free (basename);
2402 
2403 	return message;
2404 }
2405 
2406 
2407 static void
progress_dialog_set_action_description(FrWindow * window,const char * description)2408 progress_dialog_set_action_description (FrWindow   *window,
2409 					const char *description)
2410 {
2411 	char *description_markup;
2412 
2413 	description_markup = g_markup_printf_escaped ("<span weight=\"bold\" size=\"larger\">%s</span>", description);
2414 	gtk_label_set_markup (GTK_LABEL (window->priv->pd_action), description_markup);
2415 
2416 	g_free (description_markup);
2417 }
2418 
2419 
2420 static void
progress_dialog_update_action_description(FrWindow * window)2421 progress_dialog_update_action_description (FrWindow *window)
2422 {
2423 	GFile *current_archive;
2424 	char  *description;
2425 
2426 
2427 	if (window->priv->progress_dialog == NULL)
2428 		return;
2429 
2430 	if (window->priv->saving_file != NULL)
2431 		current_archive = window->priv->saving_file;
2432 	else if (window->priv->working_archive != NULL)
2433 		current_archive = window->priv->working_archive;
2434 	else
2435 		current_archive = window->priv->archive_file;
2436 
2437 	_g_clear_object (&window->priv->pd_last_archive);
2438 	if (current_archive != NULL)
2439 		window->priv->pd_last_archive = g_object_ref (current_archive);
2440 
2441 	description = get_action_description (window, window->priv->action, window->priv->pd_last_archive);
2442 	progress_dialog_set_action_description (window, description);
2443 
2444 	g_free (description);
2445 }
2446 
2447 
2448 static gboolean
fr_window_working_archive_cb(FrArchive * archive,const char * archive_uri,FrWindow * window)2449 fr_window_working_archive_cb (FrArchive  *archive,
2450 			      const char *archive_uri,
2451 			      FrWindow   *window)
2452 {
2453 	_g_clear_object (&window->priv->working_archive);
2454 	if (archive_uri != NULL)
2455 		window->priv->working_archive = g_file_new_for_uri (archive_uri);
2456 	progress_dialog_update_action_description (window);
2457 
2458 	return TRUE;
2459 }
2460 
2461 
2462 static gboolean
fr_archive_message_cb(FrArchive * archive,const char * msg,FrWindow * window)2463 fr_archive_message_cb (FrArchive  *archive,
2464 		       const char *msg,
2465 		       FrWindow   *window)
2466 {
2467 	if (window->priv->pd_last_message != msg) {
2468 		g_free (window->priv->pd_last_message);
2469 		window->priv->pd_last_message = g_strdup (msg);
2470 	}
2471 
2472 	if (window->priv->progress_dialog == NULL)
2473 		return TRUE;
2474 
2475 	if (msg != NULL) {
2476 		while (*msg == ' ')
2477 			msg++;
2478 		if (*msg == 0)
2479 			msg = NULL;
2480 	}
2481 
2482 	if (msg != NULL) {
2483 		char *utf8_msg;
2484 
2485 		if (! g_utf8_validate (msg, -1, NULL))
2486 			utf8_msg = g_locale_to_utf8 (msg, -1 , 0, 0, 0);
2487 		else
2488 			utf8_msg = g_strdup (msg);
2489 		if (utf8_msg == NULL)
2490 			return TRUE;
2491 
2492 		if (g_utf8_validate (utf8_msg, -1, NULL)) {
2493 			gtk_label_set_text (GTK_LABEL (window->priv->pd_message), utf8_msg);
2494 			gtk_widget_show (window->priv->pd_message);
2495 		}
2496 
2497 		g_free (window->priv->pd_last_message);
2498 		window->priv->pd_last_message = g_strdup (utf8_msg);
2499 
2500 		g_signal_emit (G_OBJECT (window),
2501 			       fr_window_signals[PROGRESS],
2502 			       0,
2503 			       window->priv->pd_last_fraction,
2504 			       window->priv->pd_last_message);
2505 
2506 #ifdef LOG_PROGRESS
2507 		g_print ("message > %s\n", utf8_msg);
2508 #endif
2509 
2510 		g_free (utf8_msg);
2511 	}
2512 	else
2513 		gtk_widget_hide (window->priv->pd_message);
2514 
2515 	progress_dialog_update_action_description (window);
2516 
2517 	return TRUE;
2518 }
2519 
2520 
2521 static void
fr_archive_start_cb(FrArchive * archive,FrAction action,FrWindow * window)2522 fr_archive_start_cb (FrArchive *archive,
2523 		     FrAction   action,
2524 		     FrWindow  *window)
2525 {
2526 	char *description;
2527 
2528 	description = get_action_description (window, action, fr_archive_get_file (archive));
2529 	fr_archive_message_cb (archive, description, window);
2530 
2531 	g_free (description);
2532 }
2533 
2534 
2535 static void
create_the_progress_dialog(FrWindow * window)2536 create_the_progress_dialog (FrWindow *window)
2537 {
2538 	GtkWindow      *parent;
2539 	GtkDialogFlags  flags;
2540 	const char     *title;
2541 	GtkBuilder     *builder;
2542 	gboolean        use_header_bar;
2543 	GtkWidget      *dialog;
2544 
2545 	if (window->priv->progress_dialog != NULL)
2546 		return;
2547 
2548 	if (window->priv->batch_mode) {
2549 		parent = NULL;
2550 		flags = 0;
2551 		title = window->priv->batch_title;
2552 	}
2553 	else {
2554 		parent = GTK_WINDOW (window);
2555 		flags = GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL;
2556 		title = NULL;
2557 	}
2558 
2559 	builder = _gtk_builder_new_from_resource ("progress-dialog.ui");
2560 	use_header_bar = _gtk_settings_get_dialogs_use_header ();
2561 	dialog = g_object_new (GTK_TYPE_DIALOG, "use-header-bar", use_header_bar, NULL);
2562 	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
2563 			   _gtk_builder_get_widget (builder, "progress_dialog_content"));
2564 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2565 	gtk_window_set_title (GTK_WINDOW (dialog), title);
2566 	gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
2567 	gtk_window_set_modal (GTK_WINDOW (dialog), (flags & GTK_DIALOG_MODAL));
2568 	gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), (flags & GTK_DIALOG_DESTROY_WITH_PARENT));
2569 	g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, builder);
2570 
2571 	_gtk_dialog_add_to_window_group (GTK_DIALOG (dialog));
2572 
2573 	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2574 				_GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
2575 				NULL);
2576 
2577 	if (use_header_bar) {
2578 		GtkWidget *header_bar = gtk_dialog_get_header_bar (GTK_DIALOG (dialog));
2579 		GtkWidget *cancel_button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
2580 		gtk_container_child_set (GTK_CONTAINER (header_bar), cancel_button, "pack-type", GTK_PACK_END, NULL);
2581 	}
2582 
2583 	window->priv->progress_dialog = dialog;
2584 	window->priv->pd_action = _gtk_builder_get_widget (builder, "action_label");
2585 	window->priv->pd_progress_bar = _gtk_builder_get_widget (builder, "progress_progressbar");
2586 	window->priv->pd_message = _gtk_builder_get_widget (builder, "message_label");
2587 	window->priv->pd_progress_box = _gtk_builder_get_widget (builder, "progress_box");
2588 
2589 	_g_clear_object (&window->priv->pd_last_archive);
2590 	window->priv->pd_last_archive = _g_object_ref (window->priv->archive_file);
2591 
2592 	progress_dialog_update_action_description (window);
2593 
2594 	/* signals */
2595 
2596 	g_signal_connect (G_OBJECT (window->priv->progress_dialog),
2597 			  "response",
2598 			  G_CALLBACK (progress_dialog_response),
2599 			  window);
2600 	g_signal_connect (G_OBJECT (window->priv->progress_dialog),
2601 			  "delete_event",
2602 			  G_CALLBACK (progress_dialog_delete_event),
2603 			  window);
2604 }
2605 
2606 
2607 static gboolean
display_progress_dialog(gpointer data)2608 display_progress_dialog (gpointer data)
2609 {
2610 	FrWindow *window = data;
2611 
2612 	if (window->priv->progress_timeout != 0)
2613 		g_source_remove (window->priv->progress_timeout);
2614 
2615 	if (window->priv->use_progress_dialog && (window->priv->progress_dialog != NULL)) {
2616 		gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog),
2617 						   GTK_RESPONSE_OK,
2618 						   window->priv->stoppable);
2619 		if (! window->priv->batch_mode)
2620 			gtk_window_present (GTK_WINDOW (window));
2621 		gtk_window_present (GTK_WINDOW (window->priv->progress_dialog));
2622 		fr_archive_message_cb (NULL, window->priv->pd_last_message, window);
2623 	}
2624 
2625 	window->priv->progress_timeout = 0;
2626 
2627 	return FALSE;
2628 }
2629 
2630 
2631 static void
open_progress_dialog(FrWindow * window,gboolean open_now)2632 open_progress_dialog (FrWindow *window,
2633 		      gboolean  open_now)
2634 {
2635 	if (window->priv->hide_progress_timeout != 0) {
2636 		g_source_remove (window->priv->hide_progress_timeout);
2637 		window->priv->hide_progress_timeout = 0;
2638 	}
2639 
2640 	if (open_now) {
2641 		if (window->priv->progress_timeout != 0)
2642 			g_source_remove (window->priv->progress_timeout);
2643 		window->priv->progress_timeout = 0;
2644 	}
2645 
2646 	if ((window->priv->progress_timeout != 0)
2647 	    || ((window->priv->progress_dialog != NULL) && gtk_widget_get_visible (window->priv->progress_dialog)))
2648 		return;
2649 
2650 	create_the_progress_dialog (window);
2651 	if (open_now)
2652 		display_progress_dialog (window);
2653 	else
2654 		window->priv->progress_timeout = g_timeout_add (PROGRESS_TIMEOUT_MSECS,
2655 								display_progress_dialog,
2656 								window);
2657 }
2658 
2659 
2660 static gboolean
fr_archive_progress_cb(FrArchive * archive,double fraction,FrWindow * window)2661 fr_archive_progress_cb (FrArchive *archive,
2662 		        double     fraction,
2663 		        FrWindow  *window)
2664 {
2665 	window->priv->progress_pulse = (fraction < 0.0);
2666 	if (! window->priv->progress_pulse) {
2667 		fraction = CLAMP (fraction, 0.0, 1.0);
2668 		if (window->priv->progress_dialog != NULL)
2669 			gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->pd_progress_bar), fraction);
2670 
2671 		if ((archive != NULL) && (fr_archive_progress_get_total_files (archive) > 0)) {
2672 			char *message = NULL;
2673 			int   remaining_files;
2674 
2675 			remaining_files = fr_archive_progress_get_total_files (archive) - fr_archive_progress_get_completed_files (archive);
2676 
2677 			switch (window->priv->action) {
2678 			case FR_ACTION_ADDING_FILES:
2679 			case FR_ACTION_EXTRACTING_FILES:
2680 			case FR_ACTION_DELETING_FILES:
2681 			case FR_ACTION_UPDATING_FILES:
2682 				if (remaining_files > 0)
2683 					message = g_strdup_printf (ngettext ("%d file remaining",
2684 									     "%'d files remaining",
2685 									     remaining_files), remaining_files);
2686 				else
2687 					message = g_strdup (_("Please wait…"));
2688 				break;
2689 			default:
2690 				break;
2691 			}
2692 
2693 			if (message != NULL) {
2694 				fr_archive_message (archive, message);
2695 				g_free (message);
2696 			}
2697 		}
2698 
2699 		if (fraction == 1.0)
2700 			gtk_widget_hide (window->priv->pd_progress_box);
2701 		else
2702 			gtk_widget_show (window->priv->pd_progress_box);
2703 
2704 		window->priv->pd_last_fraction = fraction;
2705 
2706 		g_signal_emit (G_OBJECT (window),
2707 			       fr_window_signals[PROGRESS],
2708 			       0,
2709 			       window->priv->pd_last_fraction,
2710 			       window->priv->pd_last_message);
2711 
2712 #ifdef LOG_PROGRESS
2713 		g_print ("progress > %2.2f\n", fraction);
2714 #endif
2715 	}
2716 	return TRUE;
2717 }
2718 
2719 
2720 /* -- confirmation dialog -- */
2721 
2722 
2723 static void
fr_window_close_confirmation_dialog(FrWindow * window,GtkWidget * dialog)2724 fr_window_close_confirmation_dialog (FrWindow  *window,
2725 				     GtkWidget *dialog)
2726 {
2727 	gtk_widget_destroy (dialog);
2728 	if (window->priv->batch_mode && window->priv->destroy_with_confirmation_dialog)
2729 		_fr_window_close_after_notification (window);
2730 }
2731 
2732 
2733 static void
confirmation_dialog_response(GtkWidget * dialog,int response_id,FrWindow * window)2734 confirmation_dialog_response (GtkWidget *dialog,
2735 			      int        response_id,
2736 			      FrWindow  *window)
2737 {
2738 	GtkWidget *new_window;
2739 	GFile     *saved_file;
2740 
2741 	saved_file = window->priv->saving_file;
2742 	window->priv->saving_file = NULL;
2743 
2744 	switch (response_id) {
2745 	case GTK_RESPONSE_CLOSE:
2746 		fr_window_close_confirmation_dialog (window, dialog);
2747 		break;
2748 
2749 	case DIALOG_RESPONSE_OPEN_ARCHIVE:
2750 		new_window = fr_window_new ();
2751 		gtk_widget_show (new_window);
2752 		fr_window_archive_open (FR_WINDOW (new_window), saved_file, GTK_WINDOW (new_window));
2753 		fr_window_close_confirmation_dialog (window, dialog);
2754 		break;
2755 
2756 	case DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER:
2757 		fr_window_view_extraction_destination_folder (window);
2758 		fr_window_close_confirmation_dialog (window, dialog);
2759 		break;
2760 
2761 	default:
2762 		break;
2763 	}
2764 
2765 	_g_object_unref (saved_file);
2766 }
2767 
2768 
2769 static gboolean
confirmation_dialog_delete_event(GtkWidget * dialog,GdkEvent * event,FrWindow * window)2770 confirmation_dialog_delete_event (GtkWidget *dialog,
2771 				  GdkEvent  *event,
2772 				  FrWindow  *window)
2773 {
2774 	fr_window_close_confirmation_dialog (window, dialog);
2775 	return TRUE;
2776 }
2777 
2778 
2779 static void
fr_window_show_confirmation_dialog(FrWindow * window,GtkWidget * dialog)2780 fr_window_show_confirmation_dialog (FrWindow  *window,
2781 				    GtkWidget *dialog)
2782 {
2783 	close_progress_dialog (window, TRUE);
2784 
2785 	g_signal_connect (G_OBJECT (dialog),
2786 			  "response",
2787 			  G_CALLBACK (confirmation_dialog_response),
2788 			  window);
2789 	g_signal_connect (G_OBJECT (dialog),
2790 			  "delete_event",
2791 			  G_CALLBACK (confirmation_dialog_delete_event),
2792 			  window);
2793 
2794 	gtk_widget_show (dialog);
2795 }
2796 
2797 
2798 static void
fr_window_show_confirmation_dialog_with_open_destination(FrWindow * window)2799 fr_window_show_confirmation_dialog_with_open_destination (FrWindow *window)
2800 {
2801 	GtkWidget *dialog;
2802 
2803 	dialog = _gtk_message_dialog_new (GTK_WINDOW (window),
2804 					  GTK_DIALOG_MODAL,
2805 					  _("Extraction completed successfully"),
2806 					  NULL,
2807 					  _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE,
2808 					  _("_Show the Files"), DIALOG_RESPONSE_OPEN_DESTINATION_FOLDER,
2809 					  NULL);
2810 
2811 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
2812 	fr_window_show_confirmation_dialog (window, dialog);
2813 }
2814 
2815 
2816 static void
fr_window_show_confirmation_dialog_with_open_archive(FrWindow * window)2817 fr_window_show_confirmation_dialog_with_open_archive (FrWindow *window)
2818 {
2819 	GtkWidget *dialog;
2820 	char      *basename;
2821 	char      *message;
2822 
2823 	basename = _g_file_get_display_basename (window->priv->saving_file);
2824 	/* Translators: %s is a filename */
2825 	message = g_strdup_printf (_("“%s” created successfully"), basename);
2826 
2827 	dialog = _gtk_message_dialog_new (GTK_WINDOW (window),
2828 					  GTK_DIALOG_MODAL,
2829 					  message,
2830 					  NULL,
2831 					  _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE,
2832 					  _("_Open the Archive"), DIALOG_RESPONSE_OPEN_ARCHIVE,
2833 					  NULL);
2834 
2835 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
2836 	fr_window_show_confirmation_dialog (window, dialog);
2837 
2838 	g_free (message);
2839 	g_free (basename);
2840 }
2841 
2842 
2843 static void
fr_window_add_to_recent_list(FrWindow * window,GFile * file)2844 fr_window_add_to_recent_list (FrWindow *window,
2845 			      GFile    *file)
2846 {
2847 	char *uri;
2848 
2849 	if (_g_file_is_temp_dir (file))
2850 		return;
2851 
2852 	uri = g_file_get_uri (file);
2853 
2854 	if (window->archive->mime_type != NULL) {
2855 		GtkRecentData *recent_data;
2856 
2857 		recent_data = g_new0 (GtkRecentData, 1);
2858 		recent_data->mime_type = g_content_type_get_mime_type (window->archive->mime_type);
2859 		recent_data->app_name = "File Roller";
2860 		recent_data->app_exec = "file-roller";
2861 		gtk_recent_manager_add_full (gtk_recent_manager_get_default (), uri, recent_data);
2862 
2863 		g_free (recent_data->mime_type);
2864 		g_free (recent_data);
2865 	}
2866 	else
2867 		gtk_recent_manager_add_item (gtk_recent_manager_get_default (), uri);
2868 
2869 	g_free (uri);
2870 }
2871 
2872 
2873 static void
fr_window_remove_from_recent_list(FrWindow * window,GFile * file)2874 fr_window_remove_from_recent_list (FrWindow *window,
2875 				   GFile    *file)
2876 {
2877 	char *uri;
2878 
2879 	if (file == NULL)
2880 		return;
2881 
2882 	uri = g_file_get_uri (file);
2883 	gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, NULL);
2884 
2885 	g_free (uri);
2886 }
2887 
2888 
2889 static void
error_dialog_response_cb(GtkDialog * dialog,gint arg1,gpointer user_data)2890 error_dialog_response_cb (GtkDialog *dialog,
2891 			  gint       arg1,
2892 			  gpointer   user_data)
2893 {
2894 	FrWindow  *window = user_data;
2895 
2896 	window->priv->showing_error_dialog = FALSE;
2897 	gtk_widget_destroy (GTK_WIDGET (dialog));
2898 
2899 	if (window->priv->destroy_with_error_dialog) {
2900 		if (window->priv->batch_mode) {
2901 			g_signal_emit (window,
2902 				       fr_window_signals[READY],
2903 				       0,
2904 				       NULL);
2905 		}
2906 		gtk_widget_destroy (GTK_WIDGET (window));
2907 	}
2908 }
2909 
2910 
2911 static void
fr_window_show_error_dialog(FrWindow * window,GtkWidget * dialog,GtkWindow * dialog_parent,const char * details)2912 fr_window_show_error_dialog (FrWindow   *window,
2913 			     GtkWidget  *dialog,
2914 			     GtkWindow  *dialog_parent,
2915 			     const char *details)
2916 {
2917 	if (window->priv->batch_mode && ! window->priv->use_progress_dialog) {
2918 		GError *error;
2919 
2920 		error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, details ? details : _("Command exited abnormally."));
2921 		g_signal_emit (window,
2922 			       fr_window_signals[READY],
2923 			       0,
2924 			       error);
2925 
2926 		gtk_widget_destroy (GTK_WIDGET (window));
2927 
2928 		return;
2929 	}
2930 
2931 	close_progress_dialog (window, TRUE);
2932 
2933 	if (window->priv->batch_mode)
2934 		fr_window_destroy_with_error_dialog (window);
2935 
2936 	g_signal_connect (dialog,
2937 			  "response",
2938 			  G_CALLBACK (error_dialog_response_cb),
2939 			  window);
2940 	if (dialog_parent != NULL)
2941 		gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
2942 	gtk_widget_show (dialog);
2943 
2944 	window->priv->showing_error_dialog = TRUE;
2945 }
2946 
2947 
2948 void
fr_window_destroy_with_error_dialog(FrWindow * window)2949 fr_window_destroy_with_error_dialog (FrWindow *window)
2950 {
2951 	window->priv->destroy_with_error_dialog = TRUE;
2952 }
2953 
2954 
2955 void
fr_window_set_notify(FrWindow * window,gboolean notify)2956 fr_window_set_notify (FrWindow   *window,
2957 		      gboolean    notify)
2958 {
2959 	window->priv->notify = notify;
2960 }
2961 
2962 
2963 static void
_handle_archive_operation_error(FrWindow * window,FrArchive * archive,FrAction action,GError * error,gboolean * continue_batch,gboolean * opens_dialog)2964 _handle_archive_operation_error (FrWindow  *window,
2965 				 FrArchive *archive,
2966 				 FrAction   action,
2967 				 GError    *error,
2968 				 gboolean  *continue_batch,
2969 				 gboolean  *opens_dialog)
2970 {
2971 	GtkWindow *dialog_parent;
2972 	char      *msg;
2973 	char      *utf8_name;
2974 	char      *details;
2975 	GList     *output;
2976 	GtkWidget *dialog;
2977 
2978 	if (continue_batch) *continue_batch = (error == NULL);
2979 	if (opens_dialog) *opens_dialog = FALSE;
2980 
2981 	if (error == NULL)
2982 		return;
2983 
2984 	if ((error != NULL) && (error->code == FR_ERROR_STOPPED))
2985 		g_cancellable_reset (window->priv->cancellable);
2986 
2987 	switch (error->code) {
2988 	case FR_ERROR_ASK_PASSWORD:
2989 		close_progress_dialog (window, TRUE);
2990 		dlg_ask_password (window);
2991 		if (opens_dialog) *opens_dialog = TRUE;
2992 		break;
2993 
2994 	case FR_ERROR_UNSUPPORTED_FORMAT:
2995 		close_progress_dialog (window, TRUE);
2996 		dlg_package_installer (window,
2997 				       window->priv->archive_file,
2998 				       action,
2999 				       window->priv->cancellable);
3000 		if (opens_dialog) *opens_dialog = TRUE;
3001 		break;
3002 
3003 #if 0
3004 	case FR_PROC_ERROR_BAD_CHARSET:
3005 		close_progress_dialog (window, TRUE);
3006 		/* dlg_ask_archive_charset (window); FIXME: implement after feature freeze */
3007 		break;
3008 #endif
3009 
3010 	case FR_ERROR_STOPPED:
3011 		/* nothing */
3012 		break;
3013 
3014 	default:
3015 		/* generic error => show an error dialog */
3016 
3017 		msg = NULL;
3018 		details = NULL;
3019 		output = NULL;
3020 
3021 		if (window->priv->batch_mode) {
3022 			dialog_parent = NULL;
3023 			window->priv->load_error_parent_window = NULL;
3024 		}
3025 		else {
3026 			dialog_parent = (GtkWindow *) window;
3027 			if (window->priv->load_error_parent_window == NULL)
3028 				window->priv->load_error_parent_window = (GtkWindow *) window;
3029 		}
3030 
3031 		switch (action) {
3032 		case FR_ACTION_CREATING_NEW_ARCHIVE:
3033 			dialog_parent = window->priv->load_error_parent_window;
3034 			msg = _("Could not create the archive");
3035 			break;
3036 
3037 		case FR_ACTION_EXTRACTING_FILES:
3038 		case FR_ACTION_COPYING_FILES_TO_REMOTE:
3039 			msg = _("An error occurred while extracting files.");
3040 			break;
3041 
3042 		case FR_ACTION_LOADING_ARCHIVE:
3043 			dialog_parent = window->priv->load_error_parent_window;
3044 			utf8_name = _g_file_get_display_basename (window->priv->archive_file);
3045 			msg = g_strdup_printf (_("Could not open “%s”"), utf8_name);
3046 			g_free (utf8_name);
3047 			break;
3048 
3049 		case FR_ACTION_LISTING_CONTENT:
3050 			msg = _("An error occurred while loading the archive.");
3051 			break;
3052 
3053 		case FR_ACTION_DELETING_FILES:
3054 			msg = _("An error occurred while deleting files from the archive.");
3055 			break;
3056 
3057 		case FR_ACTION_ADDING_FILES:
3058 		case FR_ACTION_GETTING_FILE_LIST:
3059 		case FR_ACTION_COPYING_FILES_FROM_REMOTE:
3060 			msg = _("An error occurred while adding files to the archive.");
3061 			break;
3062 
3063 		case FR_ACTION_TESTING_ARCHIVE:
3064 			msg = _("An error occurred while testing archive.");
3065 			break;
3066 
3067 		case FR_ACTION_SAVING_REMOTE_ARCHIVE:
3068 		case FR_ACTION_ENCRYPTING_ARCHIVE:
3069 			msg = _("An error occurred while saving the archive.");
3070 			break;
3071 
3072 		case FR_ACTION_RENAMING_FILES:
3073 			msg = _("An error occurred while renaming the files.");
3074 			break;
3075 
3076 		case FR_ACTION_UPDATING_FILES:
3077 			msg = _("An error occurred while updating the files.");
3078 			break;
3079 
3080 		default:
3081 			msg = _("An error occurred.");
3082 			break;
3083 		}
3084 
3085 		switch (error->code) {
3086 		case FR_ERROR_COMMAND_NOT_FOUND:
3087 			details = _("Command not found.");
3088 			break;
3089 		case FR_ERROR_EXITED_ABNORMALLY:
3090 			details = _("Command exited abnormally.");
3091 			break;
3092 		case FR_ERROR_SPAWN:
3093 			details = error->message;
3094 			break;
3095 		default:
3096 			details = error->message;
3097 			break;
3098 		}
3099 
3100 		if ((error->code != FR_ERROR_GENERIC) && FR_IS_COMMAND (archive))
3101 			output = fr_command_get_last_output (FR_COMMAND (archive));
3102 
3103 		dialog = _gtk_error_dialog_new (dialog_parent,
3104 						0,
3105 						output,
3106 						msg,
3107 						((details != NULL) ? "%s" : NULL),
3108 						details);
3109 		fr_window_show_error_dialog (window, dialog, dialog_parent, details);
3110 		break;
3111 	}
3112 }
3113 
3114 
3115 static void fr_window_batch_exec_next_action (FrWindow *window);
3116 static void fr_window_archive_list (FrWindow *window);
3117 
3118 
3119 static void
_archive_operation_completed(FrWindow * window,FrAction action,GError * error)3120 _archive_operation_completed (FrWindow *window,
3121 			      FrAction  action,
3122 			      GError   *error)
3123 {
3124 	gboolean  continue_batch = FALSE;
3125 	gboolean  opens_dialog;
3126 	gboolean  operation_canceled;
3127 	GFile    *archive_dir;
3128 	gboolean  is_temp_dir;
3129 
3130 #ifdef DEBUG
3131 	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
3132 #endif
3133 
3134 	_fr_window_stop_activity_mode (window);
3135 	_handle_archive_operation_error (window, window->archive, action, error, &continue_batch, &opens_dialog);
3136 	if (opens_dialog)
3137 		return;
3138 
3139 	operation_canceled = g_error_matches (error, FR_ERROR, FR_ERROR_STOPPED);
3140 
3141 	switch (action) {
3142 	case FR_ACTION_CREATING_NEW_ARCHIVE:
3143 	case FR_ACTION_CREATING_ARCHIVE:
3144 		close_progress_dialog (window, FALSE);
3145 		if (! operation_canceled) {
3146 			fr_window_history_clear (window);
3147 			fr_window_go_to_location (window, "/", TRUE);
3148 			fr_window_update_dir_tree (window);
3149 			fr_window_update_title (window);
3150 			fr_window_update_sensitivity (window);
3151 		}
3152 		break;
3153 
3154 	case FR_ACTION_LOADING_ARCHIVE:
3155 		close_progress_dialog (window, FALSE);
3156 		if (error != NULL) {
3157 			fr_window_remove_from_recent_list (window, window->priv->archive_file);
3158 			fr_window_archive_close (window);
3159 		}
3160 		else {
3161 			fr_window_archive_list (window);
3162 			return;
3163 		}
3164 		break;
3165 
3166 	case FR_ACTION_LISTING_CONTENT:
3167 		/* update the file because multi-volume archives can have
3168 		 * a different name after loading. */
3169 		_g_object_unref (window->priv->archive_file);
3170 		window->priv->archive_file = _g_object_ref (fr_archive_get_file (window->archive));
3171 
3172 		window->priv->reload_archive = FALSE;
3173 
3174 		close_progress_dialog (window, FALSE);
3175 		if (error != NULL) {
3176 			fr_window_remove_from_recent_list (window, window->priv->archive_file);
3177 			fr_window_archive_close (window);
3178 			fr_window_set_password (window, NULL);
3179 			break;
3180 		}
3181 
3182 		/* error == NULL */
3183 
3184 		archive_dir = g_file_get_parent (window->priv->archive_file);
3185 		is_temp_dir = _g_file_is_temp_dir (archive_dir);
3186 		if (! window->priv->archive_present) {
3187 			window->priv->archive_present = TRUE;
3188 
3189 			fr_window_history_clear (window);
3190 			fr_window_history_add (window, "/");
3191 
3192 			if (! is_temp_dir) {
3193 				fr_window_set_open_default_dir (window, archive_dir);
3194 				fr_window_set_add_default_dir (window, archive_dir);
3195 				if (! window->priv->freeze_default_dir)
3196 					fr_window_set_extract_default_dir (window, archive_dir);
3197 			}
3198 
3199 			window->priv->archive_new = FALSE;
3200 		}
3201 		g_object_unref (archive_dir);
3202 
3203 		if (! is_temp_dir)
3204 			fr_window_add_to_recent_list (window, window->priv->archive_file);
3205 
3206 		fr_window_update_history (window);
3207 		fr_window_update_title (window);
3208 		fr_window_go_to_location (window, fr_window_get_current_location (window), TRUE);
3209 		fr_window_update_dir_tree (window);
3210 
3211 		if (! window->priv->batch_mode)
3212 			gtk_window_present (GTK_WINDOW (window));
3213 		break;
3214 
3215 	case FR_ACTION_DELETING_FILES:
3216 	case FR_ACTION_ADDING_FILES:
3217 		close_progress_dialog (window, FALSE);
3218 
3219 		/* update the file because multi-volume archives can have
3220 		 * a different name after creation. */
3221 		_g_object_unref (window->priv->archive_file);
3222 		window->priv->archive_file = _g_object_ref (fr_archive_get_file (window->archive));
3223 
3224 		if (window->priv->notify) {
3225 			_g_object_unref (window->priv->saving_file);
3226 			window->priv->saving_file = g_object_ref (window->priv->archive_file);
3227 		}
3228 
3229 		if (error == NULL) {
3230 			if (window->priv->archive_new)
3231 				window->priv->archive_new = FALSE;
3232 			fr_window_add_to_recent_list (window, window->priv->archive_file);
3233 		}
3234 
3235 		if (! window->priv->batch_mode && ! operation_canceled)
3236 			window->priv->reload_archive = TRUE;
3237 
3238 		break;
3239 
3240 	case FR_ACTION_TESTING_ARCHIVE:
3241 		close_progress_dialog (window, FALSE);
3242 		if (error == NULL)
3243 			fr_window_view_last_output (window, _("Test Result"));
3244 		return;
3245 
3246 	case FR_ACTION_EXTRACTING_FILES:
3247 		close_progress_dialog (window, FALSE);
3248 		break;
3249 
3250 	case FR_ACTION_RENAMING_FILES:
3251 	case FR_ACTION_UPDATING_FILES:
3252 		close_progress_dialog (window, FALSE);
3253 		if (! window->priv->batch_mode && ! operation_canceled)
3254 			window->priv->reload_archive = TRUE;
3255 		break;
3256 
3257 	default:
3258 		close_progress_dialog (window, FALSE);
3259 		continue_batch = FALSE;
3260 		break;
3261 	}
3262 
3263 	if (continue_batch)
3264 		fr_window_batch_exec_next_action (window);
3265 	else
3266 		fr_window_batch_stop (window);
3267 }
3268 
3269 
3270 static void
_archive_operation_cancelled(FrWindow * window,FrAction action)3271 _archive_operation_cancelled (FrWindow *window,
3272 			      FrAction  action)
3273 {
3274 	GError *error;
3275 
3276 	error = g_error_new_literal (FR_ERROR, FR_ERROR_STOPPED, "");
3277 	_archive_operation_completed (window, action, error);
3278 
3279 	g_error_free (error);
3280 }
3281 
3282 
3283 static void
_archive_operation_started(FrWindow * window,FrAction action)3284 _archive_operation_started (FrWindow *window,
3285 			    FrAction  action)
3286 {
3287 	GFile *archive;
3288 
3289 	window->priv->action = action;
3290 	_fr_window_start_activity_mode (window);
3291 
3292 #ifdef DEBUG
3293 	debug (DEBUG_INFO, "%s [START] (FR::Window)\n", action_names[action]);
3294 #endif
3295 
3296 	archive = window->priv->pd_last_archive;
3297 	if (archive == NULL)
3298 		archive =  window->priv->archive_file;
3299 
3300 	switch (action) {
3301 	case FR_ACTION_EXTRACTING_FILES:
3302 		open_progress_dialog (window, ((window->priv->saving_file != NULL)
3303 					       || window->priv->batch_mode));
3304 		break;
3305 	default:
3306 		open_progress_dialog (window, window->priv->batch_mode);
3307 		break;
3308 	}
3309 
3310 	fr_archive_progress_cb (NULL, -1.0, window);
3311 	fr_archive_message_cb (NULL, _("Please wait…"), window);
3312 }
3313 
3314 
3315 /* -- selections -- */
3316 
3317 
3318 #undef DEBUG_GET_DIR_LIST_FROM_PATH
3319 
3320 
3321 static GList *
get_dir_list_from_path(FrWindow * window,char * path)3322 get_dir_list_from_path (FrWindow *window,
3323 	      		char     *path)
3324 {
3325 	char  *dirname;
3326 	int    dirname_l;
3327 	GList *list = NULL;
3328 	int    i;
3329 
3330 	if (path[strlen (path) - 1] != '/')
3331 		dirname = g_strconcat (path, "/", NULL);
3332 	else
3333 		dirname = g_strdup (path);
3334 	dirname_l = strlen (dirname);
3335 	for (i = 0; i < window->archive->files->len; i++) {
3336 		FileData *fd = g_ptr_array_index (window->archive->files, i);
3337 		gboolean  matches = FALSE;
3338 
3339 #ifdef DEBUG_GET_DIR_LIST_FROM_PATH
3340 		g_print ("%s <=> %s (%d)\n", dirname, fd->full_path, dirname_l);
3341 #endif
3342 
3343 		if (fd->dir) {
3344 			int full_path_l = strlen (fd->full_path);
3345 			if ((full_path_l == dirname_l - 1) && (strncmp (dirname, fd->full_path, full_path_l) == 0))
3346 				/* example: dirname is '/path/to/dir/' and fd->full_path is '/path/to/dir' */
3347 				matches = TRUE;
3348 			else if (strcmp (dirname, fd->full_path) == 0)
3349 				matches = TRUE;
3350 		}
3351 
3352 		if (! matches && strncmp (dirname, fd->full_path, dirname_l) == 0) {
3353 			matches = TRUE;
3354 		}
3355 
3356 		if (matches) {
3357 #ifdef DEBUG_GET_DIR_LIST_FROM_PATH
3358 			g_print ("`-> OK\n");
3359 #endif
3360 			list = g_list_prepend (list, g_strdup (fd->original_path));
3361 		}
3362 	}
3363 	g_free (dirname);
3364 
3365 	return g_list_reverse (list);
3366 }
3367 
3368 
3369 static GList *
get_dir_list_from_file_data(FrWindow * window,FileData * fdata)3370 get_dir_list_from_file_data (FrWindow *window,
3371 			     FileData *fdata)
3372 {
3373 	char  *dirname;
3374 	GList *list;
3375 
3376 	dirname = g_strconcat (fr_window_get_current_location (window),
3377 			       fdata->list_name,
3378 			       NULL);
3379 	list = get_dir_list_from_path (window, dirname);
3380 	g_free (dirname);
3381 
3382 	return list;
3383 }
3384 
3385 
3386 GList *
fr_window_get_file_list_selection(FrWindow * window,gboolean recursive,gboolean * has_dirs)3387 fr_window_get_file_list_selection (FrWindow *window,
3388 				   gboolean  recursive,
3389 				   gboolean *has_dirs)
3390 {
3391 	GtkTreeSelection *selection;
3392 	GList            *selections = NULL, *list, *scan;
3393 
3394 	g_return_val_if_fail (window != NULL, NULL);
3395 
3396 	if (has_dirs != NULL)
3397 		*has_dirs = FALSE;
3398 
3399 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3400 	if (selection == NULL)
3401 		return NULL;
3402 	gtk_tree_selection_selected_foreach (selection, add_selected_from_list_view, &selections);
3403 
3404 	list = NULL;
3405 	for (scan = selections; scan; scan = scan->next) {
3406 		FileData *fd = scan->data;
3407 
3408 		if (!fd)
3409 			continue;
3410 
3411 		if (file_data_is_dir (fd)) {
3412 			if (has_dirs != NULL)
3413 				*has_dirs = TRUE;
3414 
3415 			if (recursive)
3416 				list = g_list_concat (list, get_dir_list_from_file_data (window, fd));
3417 		}
3418 		else
3419 			list = g_list_prepend (list, g_strdup (fd->original_path));
3420 	}
3421 	if (selections)
3422 		g_list_free (selections);
3423 
3424 	return g_list_reverse (list);
3425 }
3426 
3427 
3428 GList *
fr_window_get_folder_tree_selection(FrWindow * window,gboolean recursive,gboolean * has_dirs)3429 fr_window_get_folder_tree_selection (FrWindow *window,
3430 				     gboolean  recursive,
3431 				     gboolean *has_dirs)
3432 {
3433 	GtkTreeSelection *tree_selection;
3434 	GList            *selections, *list, *scan;
3435 
3436 	g_return_val_if_fail (window != NULL, NULL);
3437 
3438 	if (has_dirs != NULL)
3439 		*has_dirs = FALSE;
3440 
3441 	tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
3442 	if (tree_selection == NULL)
3443 		return NULL;
3444 
3445 	selections = NULL;
3446 	gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_tree_view, &selections);
3447 	if (selections == NULL)
3448 		return NULL;
3449 
3450 	if (has_dirs != NULL)
3451 		*has_dirs = TRUE;
3452 
3453 	list = NULL;
3454 	for (scan = selections; scan; scan = scan->next) {
3455 		char *path = scan->data;
3456 
3457 		if (recursive)
3458 			list = g_list_concat (list, get_dir_list_from_path (window, path));
3459 	}
3460 	_g_string_list_free (selections);
3461 
3462 	return g_list_reverse (list);
3463 }
3464 
3465 
3466 GList *
fr_window_get_file_list_from_path_list(FrWindow * window,GList * path_list,gboolean * has_dirs)3467 fr_window_get_file_list_from_path_list (FrWindow *window,
3468 					GList    *path_list,
3469 					gboolean *has_dirs)
3470 {
3471 	GtkTreeModel *model;
3472 	GList        *selections, *list, *scan;
3473 
3474 	g_return_val_if_fail (window != NULL, NULL);
3475 
3476 	model = GTK_TREE_MODEL (window->priv->list_store);
3477 	selections = NULL;
3478 
3479 	if (has_dirs != NULL)
3480 		*has_dirs = FALSE;
3481 
3482 	for (scan = path_list; scan; scan = scan->next) {
3483 		GtkTreeRowReference *reference = scan->data;
3484 		GtkTreePath         *path;
3485 		GtkTreeIter          iter;
3486 		FileData            *fdata;
3487 
3488 		path = gtk_tree_row_reference_get_path (reference);
3489 		if (path == NULL)
3490 			continue;
3491 
3492 		if (! gtk_tree_model_get_iter (model, &iter, path))
3493 			continue;
3494 
3495 		gtk_tree_model_get (model, &iter,
3496 				    COLUMN_FILE_DATA, &fdata,
3497 				    -1);
3498 
3499 		selections = g_list_prepend (selections, fdata);
3500 	}
3501 
3502 	list = NULL;
3503 	for (scan = selections; scan; scan = scan->next) {
3504 		FileData *fd = scan->data;
3505 
3506 		if (!fd)
3507 			continue;
3508 
3509 		if (file_data_is_dir (fd)) {
3510 			if (has_dirs != NULL)
3511 				*has_dirs = TRUE;
3512 			list = g_list_concat (list, get_dir_list_from_file_data (window, fd));
3513 		}
3514 		else
3515 			list = g_list_prepend (list, g_strdup (fd->original_path));
3516 	}
3517 
3518 	if (selections != NULL)
3519 		g_list_free (selections);
3520 
3521 	return g_list_reverse (list);
3522 }
3523 
3524 
3525 GList *
fr_window_get_file_list_pattern(FrWindow * window,const char * pattern)3526 fr_window_get_file_list_pattern (FrWindow    *window,
3527 				 const char  *pattern)
3528 {
3529 	GRegex **regexps;
3530 	GList   *list;
3531 	int      i;
3532 
3533 	g_return_val_if_fail (window != NULL, NULL);
3534 
3535 	regexps = _g_regexp_split_from_patterns (pattern, G_REGEX_CASELESS);
3536 	list = NULL;
3537 	for (i = 0; i < window->archive->files->len; i++) {
3538 		FileData *fd = g_ptr_array_index (window->archive->files, i);
3539 		char     *utf8_name;
3540 
3541 		if (fd == NULL)
3542 			continue;
3543 
3544 		utf8_name = g_filename_to_utf8 (fd->name, -1, NULL, NULL, NULL);
3545 		if (_g_regexp_matchv (regexps, utf8_name, 0))
3546 			list = g_list_prepend (list, g_strdup (fd->original_path));
3547 		g_free (utf8_name);
3548 	}
3549 	_g_regexp_freev (regexps);
3550 
3551 	return g_list_reverse (list);
3552 }
3553 
3554 
3555 static GList *
fr_window_get_file_list(FrWindow * window)3556 fr_window_get_file_list (FrWindow *window)
3557 {
3558 	GList *list;
3559 	int    i;
3560 
3561 	g_return_val_if_fail (window != NULL, NULL);
3562 
3563 	list = NULL;
3564 	for (i = 0; i < window->archive->files->len; i++) {
3565 		FileData *fd = g_ptr_array_index (window->archive->files, i);
3566 		list = g_list_prepend (list, g_strdup (fd->original_path));
3567 	}
3568 
3569 	return g_list_reverse (list);
3570 }
3571 
3572 
3573 int
fr_window_get_n_selected_files(FrWindow * window)3574 fr_window_get_n_selected_files (FrWindow *window)
3575 {
3576 	return _gtk_tree_selection_count_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
3577 }
3578 
3579 
3580 /**/
3581 
3582 
3583 static int
dir_tree_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)3584 dir_tree_button_press_cb (GtkWidget      *widget,
3585 			  GdkEventButton *event,
3586 			  gpointer        data)
3587 {
3588 	FrWindow         *window = data;
3589 	GtkTreeSelection *selection;
3590 
3591 	if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->tree_view)))
3592 		return FALSE;
3593 
3594 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
3595 	if (selection == NULL)
3596 		return FALSE;
3597 
3598 	if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
3599 		GtkTreePath *path;
3600 		GtkTreeIter  iter;
3601 
3602 		if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->tree_view),
3603 						   event->x, event->y,
3604 						   &path, NULL, NULL, NULL)) {
3605 
3606 			if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->tree_store), &iter, path)) {
3607 				gtk_tree_path_free (path);
3608 				return FALSE;
3609 			}
3610 			gtk_tree_path_free (path);
3611 
3612 			if (! gtk_tree_selection_iter_is_selected (selection, &iter)) {
3613 				gtk_tree_selection_unselect_all (selection);
3614 				gtk_tree_selection_select_iter (selection, &iter);
3615 			}
3616 
3617 			gtk_menu_popup_at_pointer (GTK_MENU (window->priv->sidebar_folder_popup_menu), (GdkEvent *) event);
3618 		}
3619 		else
3620 			gtk_tree_selection_unselect_all (selection);
3621 
3622 		return TRUE;
3623 	}
3624 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 8)) {
3625 		fr_window_go_back (window);
3626 		return TRUE;
3627 	}
3628 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 9)) {
3629 		fr_window_go_forward (window);
3630 		return TRUE;
3631 	}
3632 
3633 	return FALSE;
3634 }
3635 
3636 
3637 static FileData *
fr_window_get_selected_item_from_file_list(FrWindow * window)3638 fr_window_get_selected_item_from_file_list (FrWindow *window)
3639 {
3640 	GtkTreeSelection *tree_selection;
3641 	GList            *selection;
3642 	FileData         *fdata = NULL;
3643 
3644 	g_return_val_if_fail (window != NULL, NULL);
3645 
3646 	tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3647 	if (tree_selection == NULL)
3648 		return NULL;
3649 
3650 	selection = NULL;
3651 	gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_list_view, &selection);
3652 	if ((selection == NULL) || (selection->next != NULL)) {
3653 		/* return NULL if the selection contains more than one entry. */
3654 		g_list_free (selection);
3655 		return NULL;
3656 	}
3657 
3658 	fdata = file_data_copy (selection->data);
3659 	g_list_free (selection);
3660 
3661 	return fdata;
3662 }
3663 
3664 
3665 static char *
fr_window_get_selected_folder_in_tree_view(FrWindow * window)3666 fr_window_get_selected_folder_in_tree_view (FrWindow *window)
3667 {
3668 	GtkTreeSelection *tree_selection;
3669 	GList            *selections;
3670 	char             *path = NULL;
3671 
3672 	g_return_val_if_fail (window != NULL, NULL);
3673 
3674 	tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
3675 	if (tree_selection == NULL)
3676 		return NULL;
3677 
3678 	selections = NULL;
3679 	gtk_tree_selection_selected_foreach (tree_selection, add_selected_from_tree_view, &selections);
3680 
3681 	if (selections != NULL) {
3682 		path = selections->data;
3683 		g_list_free (selections);
3684 	}
3685 
3686 	return path;
3687 }
3688 
3689 
3690 void
fr_window_current_folder_activated(FrWindow * window,gboolean from_sidebar)3691 fr_window_current_folder_activated (FrWindow *window,
3692 				    gboolean   from_sidebar)
3693 {
3694 	char *dir_path;
3695 
3696 	if (! from_sidebar) {
3697 		FileData *fdata;
3698 		char     *dir_name;
3699 
3700 		fdata = fr_window_get_selected_item_from_file_list (window);
3701 		if ((fdata == NULL) || ! file_data_is_dir (fdata)) {
3702 			file_data_free (fdata);
3703 			return;
3704 		}
3705 		dir_name = g_strdup (fdata->list_name);
3706 		dir_path = g_strconcat (fr_window_get_current_location (window),
3707 					dir_name,
3708 					"/",
3709 					NULL);
3710 		g_free (dir_name);
3711 		file_data_free (fdata);
3712 	}
3713 	else
3714 		dir_path = fr_window_get_selected_folder_in_tree_view (window);
3715 
3716 	fr_window_go_to_location (window, dir_path, FALSE);
3717 
3718 	g_free (dir_path);
3719 }
3720 
3721 
3722 static gboolean
row_activated_cb(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)3723 row_activated_cb (GtkTreeView       *tree_view,
3724 		  GtkTreePath       *path,
3725 		  GtkTreeViewColumn *column,
3726 		  gpointer           data)
3727 {
3728 	FrWindow    *window = data;
3729 	FileData    *fdata;
3730 	GtkTreeIter  iter;
3731 
3732 	if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3733 				       &iter,
3734 				       path))
3735 		return FALSE;
3736 
3737 	gtk_tree_model_get (GTK_TREE_MODEL (window->priv->list_store), &iter,
3738 			    COLUMN_FILE_DATA, &fdata,
3739 			    -1);
3740 
3741 	if (! file_data_is_dir (fdata)) {
3742 		GList *list = g_list_prepend (NULL, fdata->original_path);
3743 		fr_window_open_files (window, list, FALSE);
3744 		g_list_free (list);
3745 	}
3746 	else if (window->priv->list_mode == FR_WINDOW_LIST_MODE_AS_DIR) {
3747 		char *new_dir;
3748 		new_dir = g_strconcat (fr_window_get_current_location (window),
3749 				       fdata->list_name,
3750 				       "/",
3751 				       NULL);
3752 		fr_window_go_to_location (window, new_dir, FALSE);
3753 		g_free (new_dir);
3754 	}
3755 
3756 	return FALSE;
3757 }
3758 
3759 
3760 static int
file_button_press_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)3761 file_button_press_cb (GtkWidget      *widget,
3762 		      GdkEventButton *event,
3763 		      gpointer        data)
3764 {
3765 	FrWindow         *window = data;
3766 	GtkTreeSelection *selection;
3767 
3768 	if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)))
3769 		return FALSE;
3770 
3771 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3772 	if (selection == NULL)
3773 		return FALSE;
3774 
3775 	if (window->priv->path_clicked != NULL) {
3776 		gtk_tree_path_free (window->priv->path_clicked);
3777 		window->priv->path_clicked = NULL;
3778 	}
3779 
3780 	if ((event->type == GDK_BUTTON_PRESS) && (event->button == 3)) {
3781 		GtkTreePath *path;
3782 		GtkTreeIter  iter;
3783 		int          n_selected;
3784 
3785 		if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
3786 						   event->x, event->y,
3787 						   &path, NULL, NULL, NULL)) {
3788 
3789 			if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store), &iter, path)) {
3790 				gtk_tree_path_free (path);
3791 				return FALSE;
3792 			}
3793 			gtk_tree_path_free (path);
3794 
3795 			if (! gtk_tree_selection_iter_is_selected (selection, &iter)) {
3796 				gtk_tree_selection_unselect_all (selection);
3797 				gtk_tree_selection_select_iter (selection, &iter);
3798 			}
3799 		}
3800 		else
3801 			gtk_tree_selection_unselect_all (selection);
3802 
3803 		n_selected = fr_window_get_n_selected_files (window);
3804 		if ((n_selected == 1) && selection_has_a_dir (window))
3805 			gtk_menu_popup_at_pointer (GTK_MENU (window->priv->folder_popup_menu),  (GdkEvent *) event);
3806 		else
3807 			gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (GdkEvent *) event);
3808 		return TRUE;
3809 	}
3810 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 1)) {
3811 		GtkTreePath *path = NULL;
3812 
3813 		if (! gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
3814 						     event->x, event->y,
3815 						     &path, NULL, NULL, NULL)) {
3816 			gtk_tree_selection_unselect_all (selection);
3817 		}
3818 
3819 		if (window->priv->path_clicked != NULL) {
3820 			gtk_tree_path_free (window->priv->path_clicked);
3821 			window->priv->path_clicked = NULL;
3822 		}
3823 
3824 		if (path != NULL) {
3825 			window->priv->path_clicked = gtk_tree_path_copy (path);
3826 			gtk_tree_path_free (path);
3827 		}
3828 
3829 		return FALSE;
3830 	}
3831 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 8)) {
3832 		// go back
3833 		fr_window_go_back (window);
3834 		return TRUE;
3835 	}
3836 	else if ((event->type == GDK_BUTTON_PRESS) && (event->button == 9)) {
3837 		// go forward
3838 		fr_window_go_forward (window);
3839 		return TRUE;
3840 	}
3841 
3842 	return FALSE;
3843 }
3844 
3845 
3846 static int
file_button_release_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)3847 file_button_release_cb (GtkWidget      *widget,
3848 			GdkEventButton *event,
3849 			gpointer        data)
3850 {
3851 	FrWindow         *window = data;
3852 	GtkTreeSelection *selection;
3853 
3854 	if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)))
3855 		return FALSE;
3856 
3857 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
3858 	if (selection == NULL)
3859 		return FALSE;
3860 
3861 	if (window->priv->path_clicked == NULL)
3862 		return FALSE;
3863 
3864 	if ((event->type == GDK_BUTTON_RELEASE)
3865 	    && (event->button == 1)
3866 	    && (window->priv->path_clicked != NULL)) {
3867 		GtkTreePath *path = NULL;
3868 
3869 		if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (window->priv->list_view),
3870 						   event->x, event->y,
3871 						   &path, NULL, NULL, NULL)) {
3872 
3873 			if ((gtk_tree_path_compare (window->priv->path_clicked, path) == 0)
3874 			    && window->priv->single_click
3875 			    && ! ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_SHIFT_MASK))) {
3876 				gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget),
3877 							  path,
3878 							  NULL,
3879 							  FALSE);
3880 				gtk_tree_view_row_activated (GTK_TREE_VIEW (widget),
3881 							     path,
3882 							     NULL);
3883 			}
3884 		}
3885 
3886 		if (path != NULL)
3887 			gtk_tree_path_free (path);
3888 	}
3889 
3890 	if (window->priv->path_clicked != NULL) {
3891 		gtk_tree_path_free (window->priv->path_clicked);
3892 		window->priv->path_clicked = NULL;
3893 	}
3894 
3895 	return FALSE;
3896 }
3897 
3898 
3899 static gboolean
file_motion_notify_callback(GtkWidget * widget,GdkEventMotion * event,gpointer user_data)3900 file_motion_notify_callback (GtkWidget *widget,
3901 			     GdkEventMotion *event,
3902 			     gpointer user_data)
3903 {
3904 	FrWindow    *window = user_data;
3905 	GdkCursor   *cursor;
3906 	GtkTreePath *last_hover_path;
3907 	GtkTreeIter  iter;
3908 
3909 	if (! window->priv->single_click)
3910 		return FALSE;
3911 
3912 	if (event->window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view)))
3913 		return FALSE;
3914 
3915 	last_hover_path = window->priv->list_hover_path;
3916 
3917 	gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
3918 				       event->x, event->y,
3919 				       &window->priv->list_hover_path,
3920 				       NULL, NULL, NULL);
3921 
3922 	if (window->priv->list_hover_path != NULL)
3923 		cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (window)),
3924 						     GDK_HAND2);
3925 	else
3926 		cursor = NULL;
3927 
3928 	gdk_window_set_cursor (event->window, cursor);
3929 
3930 	if (cursor != NULL)
3931 		g_object_unref (cursor);
3932 
3933 	/* only redraw if the hover row has changed */
3934 	if (!(last_hover_path == NULL && window->priv->list_hover_path == NULL) &&
3935 	    (!(last_hover_path != NULL && window->priv->list_hover_path != NULL) ||
3936 	     gtk_tree_path_compare (last_hover_path, window->priv->list_hover_path)))
3937 	{
3938 		if (last_hover_path) {
3939 			gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3940 						 &iter, last_hover_path);
3941 			gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store),
3942 						    last_hover_path, &iter);
3943 		}
3944 
3945 		if (window->priv->list_hover_path) {
3946 			gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3947 						 &iter, window->priv->list_hover_path);
3948 			gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store),
3949 						    window->priv->list_hover_path, &iter);
3950 		}
3951 	}
3952 
3953 	gtk_tree_path_free (last_hover_path);
3954 
3955  	return FALSE;
3956 }
3957 
3958 
3959 static gboolean
file_leave_notify_callback(GtkWidget * widget,GdkEventCrossing * event,gpointer user_data)3960 file_leave_notify_callback (GtkWidget *widget,
3961 			    GdkEventCrossing *event,
3962 			    gpointer user_data)
3963 {
3964 	FrWindow    *window = user_data;
3965 	GtkTreeIter  iter;
3966 
3967 	if (window->priv->single_click && (window->priv->list_hover_path != NULL)) {
3968 		gtk_tree_model_get_iter (GTK_TREE_MODEL (window->priv->list_store),
3969 					 &iter,
3970 					 window->priv->list_hover_path);
3971 		gtk_tree_model_row_changed (GTK_TREE_MODEL (window->priv->list_store),
3972 					    window->priv->list_hover_path,
3973 					    &iter);
3974 
3975 		gtk_tree_path_free (window->priv->list_hover_path);
3976 		window->priv->list_hover_path = NULL;
3977 	}
3978 
3979 	return FALSE;
3980 }
3981 
3982 
3983 /* -- drag and drop -- */
3984 
3985 
3986 static GList *
get_file_list_from_selection_data(char * uri_list)3987 get_file_list_from_selection_data (char *uri_list)
3988 {
3989 	GList  *list = NULL;
3990 	char  **uris;
3991 	int     i;
3992 
3993 	if (uri_list == NULL)
3994 		return NULL;
3995 
3996 	uris = g_uri_list_extract_uris (uri_list);
3997 	for (i = 0; uris[i] != NULL; i++)
3998 		list = g_list_prepend (list, g_file_new_for_uri (uris[i]));
3999 	g_strfreev (uris);
4000 
4001 	return g_list_reverse (list);
4002 }
4003 
4004 
4005 static gboolean
fr_window_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,gpointer user_data)4006 fr_window_drag_motion (GtkWidget      *widget,
4007 		       GdkDragContext *context,
4008 		       gint            x,
4009 		       gint            y,
4010 		       guint           time,
4011 		       gpointer        user_data)
4012 {
4013 	FrWindow  *window = user_data;
4014 
4015 	if ((gtk_drag_get_source_widget (context) == window->priv->list_view)
4016 	    || (gtk_drag_get_source_widget (context) == window->priv->tree_view))
4017 	{
4018 		gdk_drag_status (context, 0, time);
4019 		return FALSE;
4020 	}
4021 
4022 	return TRUE;
4023 }
4024 
4025 
4026 static void fr_window_paste_from_clipboard_data (FrWindow *window, FrClipboardData *data);
4027 
4028 
4029 static FrClipboardData*
get_clipboard_data_from_selection_data(FrWindow * window,const char * data)4030 get_clipboard_data_from_selection_data (FrWindow   *window,
4031 					const char *data)
4032 {
4033 	FrClipboardData  *clipboard_data;
4034 	char            **uris;
4035 	int               i;
4036 
4037 	clipboard_data = fr_clipboard_data_new ();
4038 
4039 	uris = g_strsplit (data, "\r\n", -1);
4040 
4041 	clipboard_data->file = g_file_new_for_uri (uris[0]);
4042 	if (window->priv->second_password != NULL)
4043 		clipboard_data->password = g_strdup (window->priv->second_password);
4044 	else if (strcmp (uris[1], "") != 0)
4045 		clipboard_data->password = g_strdup (uris[1]);
4046 	clipboard_data->op = (strcmp (uris[2], "copy") == 0) ? FR_CLIPBOARD_OP_COPY : FR_CLIPBOARD_OP_CUT;
4047 	clipboard_data->base_dir = g_strdup (uris[3]);
4048 	for (i = 4; uris[i] != NULL; i++)
4049 		if (uris[i][0] != '\0')
4050 			clipboard_data->files = g_list_prepend (clipboard_data->files, g_strdup (uris[i]));
4051 	clipboard_data->files = g_list_reverse (clipboard_data->files);
4052 
4053 	g_strfreev (uris);
4054 
4055 	return clipboard_data;
4056 }
4057 
4058 
4059 gboolean
fr_window_create_archive_and_continue(FrWindow * window,GFile * file,const char * mime_type,GtkWindow * error_dialog_parent)4060 fr_window_create_archive_and_continue (FrWindow   *window,
4061 			  	       GFile      *file,
4062 			  	       const char *mime_type,
4063 			  	       GtkWindow  *error_dialog_parent)
4064 {
4065 	gboolean result = FALSE;
4066 
4067 	if (fr_window_archive_new (FR_WINDOW (window), file, mime_type)) {
4068 		if (! fr_window_is_batch_mode (FR_WINDOW (window)))
4069 			gtk_window_present (GTK_WINDOW (window));
4070 		_archive_operation_completed (window, FR_ACTION_CREATING_NEW_ARCHIVE, NULL);
4071 
4072 		result = TRUE;
4073 	}
4074 	else {
4075 		GError *error;
4076 
4077 		error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, _("Archive type not supported."));
4078 		window->priv->load_error_parent_window = error_dialog_parent;
4079 		_archive_operation_completed (window, FR_ACTION_CREATING_NEW_ARCHIVE, error);
4080 
4081 		g_error_free (error);
4082 
4083 		result = FALSE;
4084 	}
4085 
4086 	return result;
4087 }
4088 
4089 
4090 static gboolean
_fr_window_get_ask_to_open_destination(FrWindow * window)4091 _fr_window_get_ask_to_open_destination (FrWindow *window)
4092 {
4093 	return ! window->priv->batch_mode || window->priv->notify;
4094 }
4095 
4096 
4097 static void
new_archive_dialog_response_cb(GtkDialog * dialog,int response,gpointer user_data)4098 new_archive_dialog_response_cb (GtkDialog *dialog,
4099 				int        response,
4100 				gpointer   user_data)
4101 {
4102 	FrWindow   *window = user_data;
4103 	GFile      *file;
4104 	const char *mime_type;
4105 	GtkWidget  *archive_window;
4106 	gboolean    new_window;
4107 	const char *password;
4108 	gboolean    encrypt_header;
4109 	int         volume_size;
4110 
4111 	if ((response == GTK_RESPONSE_CANCEL) || (response == GTK_RESPONSE_DELETE_EVENT)) {
4112 		gtk_widget_destroy (GTK_WIDGET (dialog));
4113 		_archive_operation_cancelled (window, FR_ACTION_CREATING_NEW_ARCHIVE);
4114 		return;
4115 	}
4116 
4117 	file = fr_new_archive_dialog_get_file (FR_NEW_ARCHIVE_DIALOG (dialog), &mime_type);
4118 	if (file == NULL)
4119 		return;
4120 
4121 	new_window = fr_window_archive_is_present (window) && ! fr_window_is_batch_mode (window);
4122 	if (new_window)
4123 		archive_window = fr_window_new ();
4124 	else
4125 		archive_window = (GtkWidget *) window;
4126 
4127 	password = fr_new_archive_dialog_get_password (FR_NEW_ARCHIVE_DIALOG (dialog));
4128 	encrypt_header = fr_new_archive_dialog_get_encrypt_header (FR_NEW_ARCHIVE_DIALOG (dialog));
4129 	volume_size = fr_new_archive_dialog_get_volume_size (FR_NEW_ARCHIVE_DIALOG (dialog));
4130 
4131 	fr_window_set_password (FR_WINDOW (archive_window), password);
4132 	fr_window_set_encrypt_header (FR_WINDOW (archive_window), encrypt_header);
4133 	fr_window_set_volume_size (FR_WINDOW (archive_window), volume_size);
4134 
4135 	if (fr_window_create_archive_and_continue (FR_WINDOW (archive_window),
4136 						   file,
4137 						   mime_type,
4138 						   GTK_WINDOW (dialog)))
4139 	{
4140 		gtk_widget_destroy (GTK_WIDGET (dialog));
4141 	}
4142 	else if (new_window)
4143 		gtk_widget_destroy (archive_window);
4144 
4145 	g_object_unref (file);
4146 }
4147 
4148 
4149 static void
fr_window_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,gpointer extra_data)4150 fr_window_drag_data_received  (GtkWidget          *widget,
4151 			       GdkDragContext     *context,
4152 			       gint                x,
4153 			       gint                y,
4154 			       GtkSelectionData   *data,
4155 			       guint               info,
4156 			       guint               time,
4157 			       gpointer            extra_data)
4158 {
4159 	FrWindow  *window = extra_data;
4160 	GList     *list;
4161 	gboolean   one_file;
4162 	gboolean   is_an_archive;
4163 
4164 	debug (DEBUG_INFO, "::DragDataReceived -->\n");
4165 
4166 	if ((gtk_drag_get_source_widget (context) == window->priv->list_view)
4167 	    || (gtk_drag_get_source_widget (context) == window->priv->tree_view))
4168 	{
4169 		gtk_drag_finish (context, FALSE, FALSE, time);
4170 		return;
4171 	}
4172 
4173 	if (! ((gtk_selection_data_get_length (data) >= 0) && (gtk_selection_data_get_format (data) == 8))) {
4174 		gtk_drag_finish (context, FALSE, FALSE, time);
4175 		return;
4176 	}
4177 
4178 	if (window->priv->activity_ref > 0) {
4179 		gtk_drag_finish (context, FALSE, FALSE, time);
4180 		return;
4181 	}
4182 
4183 	gtk_drag_finish (context, TRUE, FALSE, time);
4184 
4185 	if (gtk_selection_data_get_target (data) == XFR_ATOM) {
4186 		FrClipboardData *dnd_data;
4187 
4188 		dnd_data = get_clipboard_data_from_selection_data (window, (char*) gtk_selection_data_get_data (data));
4189 		dnd_data->current_dir = g_strdup (fr_window_get_current_location (window));
4190 		fr_window_paste_from_clipboard_data (window, dnd_data);
4191 
4192 		return;
4193 	}
4194 
4195 	list = get_file_list_from_selection_data ((char*) gtk_selection_data_get_data (data));
4196 	if (list == NULL) {
4197 		GtkWidget *d;
4198 
4199 		d = _gtk_error_dialog_new (GTK_WINDOW (window),
4200 					   GTK_DIALOG_MODAL,
4201 					   NULL,
4202 					   _("Could not perform the operation"),
4203 					   NULL);
4204 		gtk_dialog_run (GTK_DIALOG (d));
4205 		gtk_widget_destroy(d);
4206 
4207  		return;
4208 	}
4209 
4210 	one_file = (list->next == NULL);
4211 	if (one_file)
4212 		is_an_archive = _g_file_is_archive (G_FILE (list->data));
4213 	else
4214 		is_an_archive = FALSE;
4215 
4216 	if (window->priv->archive_present
4217 	    && (window->archive != NULL)
4218 	    && ! window->archive->read_only
4219 	    && fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_STORE_MANY_FILES))
4220 	{
4221 		if (one_file && is_an_archive) {
4222 			GtkWidget *d;
4223 			gint       r;
4224 
4225 			d = _gtk_message_dialog_new (GTK_WINDOW (window),
4226 						     GTK_DIALOG_MODAL,
4227 						     _("Do you want to add this file to the current archive or open it as a new archive?"),
4228 						     NULL,
4229 						     _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
4230 						     _GTK_LABEL_ADD, 0,
4231 						     _GTK_LABEL_OPEN, 1,
4232 						     NULL);
4233 
4234 			gtk_dialog_set_default_response (GTK_DIALOG (d), 2);
4235 
4236 			r = gtk_dialog_run (GTK_DIALOG (d));
4237 			gtk_widget_destroy (GTK_WIDGET (d));
4238 
4239 			if (r == 0)  /* Add */
4240 				fr_window_archive_add_dropped_items (window, list);
4241 			else if (r == 1)  /* Open */
4242 				fr_window_archive_open (window, G_FILE (list->data), GTK_WINDOW (window));
4243  		}
4244  		else
4245 			fr_window_archive_add_dropped_items (window, list);
4246 	}
4247 	else {
4248 		if (one_file && is_an_archive)
4249 			fr_window_archive_open (window, G_FILE (list->data), GTK_WINDOW (window));
4250 		else {
4251 			GtkWidget *d;
4252 			int        r;
4253 
4254 			d = _gtk_message_dialog_new (GTK_WINDOW (window),
4255 						     GTK_DIALOG_MODAL,
4256 						     _("Do you want to create a new archive with these files?"),
4257 						     NULL,
4258 						     _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
4259 						     _("Create _Archive"), GTK_RESPONSE_YES,
4260 						     NULL);
4261 
4262 			gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES);
4263 			r = gtk_dialog_run (GTK_DIALOG (d));
4264 			gtk_widget_destroy (GTK_WIDGET (d));
4265 
4266 			if (r == GTK_RESPONSE_YES) {
4267 				GFile     *first_file;
4268 				GFile     *folder;
4269 				char      *archive_name;
4270 				GtkWidget *dialog;
4271 
4272 				fr_window_free_batch_data (window);
4273 				fr_window_batch_append_action (window,
4274 							       FR_BATCH_ACTION_ADD,
4275 							       _g_object_list_ref (list),
4276 							       (GFreeFunc) _g_object_list_unref);
4277 
4278 				first_file = G_FILE (list->data);
4279 				folder = g_file_get_parent (first_file);
4280 				if (folder != NULL)
4281 					fr_window_set_open_default_dir (window, folder);
4282 
4283 				if ((list->next != NULL) && (folder != NULL))
4284 					archive_name = g_file_get_basename (folder);
4285 				else
4286 					archive_name = g_file_get_basename (first_file);
4287 
4288 				dialog = fr_new_archive_dialog_new (_("New Archive"),
4289 								    GTK_WINDOW (window),
4290 								    FR_NEW_ARCHIVE_ACTION_SAVE_AS,
4291 								    fr_window_get_open_default_dir (window),
4292 								    archive_name,
4293 								    NULL);
4294 				gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4295 				g_signal_connect (G_OBJECT (dialog),
4296 						  "response",
4297 						  G_CALLBACK (new_archive_dialog_response_cb),
4298 						  window);
4299 				gtk_window_present (GTK_WINDOW (dialog));
4300 
4301 				g_free (archive_name);
4302 				_g_object_unref (folder);
4303 			}
4304 		}
4305 	}
4306 
4307 	_g_object_list_unref (list);
4308 
4309 	debug (DEBUG_INFO, "::DragDataReceived <--\n");
4310 }
4311 
4312 
4313 static gboolean
tree_view_drag_begin(GtkWidget * widget,GdkDragContext * context,GtkTreeModel * tree_model,int filename_column,gpointer data)4314 tree_view_drag_begin (GtkWidget          *widget,
4315 		      GdkDragContext     *context,
4316 		      GtkTreeModel	 *tree_model,
4317 		      int		  filename_column,
4318 		      gpointer            data)
4319 {
4320 	FrWindow         *window = data;
4321 	GtkTreeSelection *selection;
4322 	GtkTreeIter       iter;
4323 	GList            *selected_tree_paths;
4324 	char             *xds_filename;
4325 
4326 	debug (DEBUG_INFO, "::DragBegin -->\n");
4327 
4328 	if (window->priv->activity_ref > 0)
4329 		return FALSE;
4330 
4331 	if (window->priv->path_clicked != NULL) {
4332 		gtk_tree_path_free (window->priv->path_clicked);
4333 		window->priv->path_clicked = NULL;
4334 	}
4335 
4336 	_g_clear_object (&window->priv->drag_destination_folder);
4337 
4338 	g_free (window->priv->drag_base_dir);
4339 	window->priv->drag_base_dir = NULL;
4340 
4341 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
4342 	selected_tree_paths = gtk_tree_selection_get_selected_rows (selection, NULL);
4343 
4344 	if (gtk_tree_model_get_iter (tree_model,
4345 				     &iter,
4346 				     (GtkTreePath *) selected_tree_paths->data))
4347 	{
4348 		gtk_tree_model_get (tree_model,
4349 				    &iter,
4350 				    filename_column, &xds_filename,
4351 				    -1);
4352 	}
4353 	else
4354 		xds_filename = g_strdup (XDS_FILENAME);
4355 
4356 	gdk_property_change (gdk_drag_context_get_source_window (context),
4357 			     XDS_ATOM, TEXT_ATOM,
4358 			     8, GDK_PROP_MODE_REPLACE,
4359 			     (guchar *) xds_filename,
4360 			     strlen (xds_filename));
4361 
4362 	g_free (xds_filename);
4363 	g_list_free_full (selected_tree_paths, (GDestroyNotify) gtk_tree_path_free);
4364 
4365 	return TRUE;
4366 }
4367 
4368 
4369 static gboolean
file_list_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)4370 file_list_drag_begin (GtkWidget          *widget,
4371 		      GdkDragContext     *context,
4372 		      gpointer            data)
4373 {
4374 	FrWindow *window = data;
4375 	return tree_view_drag_begin (widget,
4376 				     context,
4377 				     GTK_TREE_MODEL (window->priv->list_store),
4378 				     COLUMN_NAME,
4379 				     data);
4380 }
4381 
4382 
4383 static gboolean
folde_tree_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)4384 folde_tree_drag_begin (GtkWidget          *widget,
4385 		       GdkDragContext     *context,
4386 		       gpointer            data)
4387 {
4388 	FrWindow *window = data;
4389 	return tree_view_drag_begin (widget,
4390 				     context,
4391 				     GTK_TREE_MODEL (window->priv->tree_store),
4392 				     TREE_COLUMN_NAME,
4393 				     data);
4394 }
4395 
4396 
4397 static void
file_list_drag_end(GtkWidget * widget,GdkDragContext * context,gpointer data)4398 file_list_drag_end (GtkWidget      *widget,
4399 		    GdkDragContext *context,
4400 		    gpointer        data)
4401 {
4402 	FrWindow *window = data;
4403 
4404 	debug (DEBUG_INFO, "::DragEnd -->\n");
4405 
4406 	gdk_property_delete (gdk_drag_context_get_source_window (context), XDS_ATOM);
4407 
4408 	if (window->priv->drag_error != NULL) {
4409 		_gtk_error_dialog_run (GTK_WINDOW (window),
4410 				       _("Extraction not performed"),
4411 				       "%s",
4412 				       window->priv->drag_error->message);
4413 		g_clear_error (&window->priv->drag_error);
4414 	}
4415 	else if (window->priv->drag_destination_folder != NULL) {
4416 		_g_string_list_free (window->priv->drag_file_list);
4417 		window->priv->drag_file_list = NULL;
4418 	}
4419 
4420 	debug (DEBUG_INFO, "::DragEnd <--\n");
4421 }
4422 
4423 
4424 /* The following three functions taken from bugzilla
4425  * (http://bugzilla.gnome.org/attachment.cgi?id=49362&action=view)
4426  * Author: Christian Neumair
4427  * Copyright: 2005 Free Software Foundation, Inc
4428  * License: GPL */
4429 static char *
get_xds_atom_value(GdkDragContext * context)4430 get_xds_atom_value (GdkDragContext *context)
4431 {
4432 	char *data = NULL;
4433 	char *ret;
4434 	int   len;
4435 
4436 	g_return_val_if_fail (context != NULL, NULL);
4437 	g_return_val_if_fail (gdk_drag_context_get_source_window (context) != NULL, NULL);
4438 
4439 	if (gdk_property_get (gdk_drag_context_get_source_window (context),
4440 			      XDS_ATOM, TEXT_ATOM,
4441 			      0, MAX_XDS_ATOM_VAL_LEN,
4442 			      FALSE, NULL, NULL, &len,
4443 			      (unsigned char **) &ret))
4444 	{
4445 		data = g_strndup (ret, len);
4446 		g_free (ret);
4447 	}
4448 
4449 	return data;
4450 }
4451 
4452 
4453 static gboolean
context_offers_target(GdkDragContext * context,GdkAtom target)4454 context_offers_target (GdkDragContext *context,
4455 		       GdkAtom target)
4456 {
4457 	return (g_list_find (gdk_drag_context_list_targets (context), target) != NULL);
4458 }
4459 
4460 
4461 static gboolean
nautilus_xds_dnd_is_valid_xds_context(GdkDragContext * context)4462 nautilus_xds_dnd_is_valid_xds_context (GdkDragContext *context)
4463 {
4464 	gboolean ret = FALSE;
4465 
4466 	g_return_val_if_fail (context != NULL, FALSE);
4467 
4468 	if (context_offers_target (context, XDS_ATOM)) {
4469 		char *tmp = get_xds_atom_value (context);
4470 		ret = (tmp != NULL);
4471 		g_free (tmp);
4472 	}
4473 
4474 	return ret;
4475 }
4476 
4477 
4478 static char *
get_selection_data_from_clipboard_data(FrWindow * window,FrClipboardData * data)4479 get_selection_data_from_clipboard_data (FrWindow        *window,
4480 		      			FrClipboardData *data)
4481 {
4482 	GString *list;
4483 	char    *uri;
4484 	GList   *scan;
4485 
4486 	if (data == NULL)
4487 		return NULL;
4488 
4489 	list = g_string_new (NULL);
4490 
4491 	uri = g_file_get_uri (fr_archive_get_file (window->archive));
4492 	g_string_append (list, uri);
4493 	g_free (uri);
4494 
4495 	g_string_append (list, "\r\n");
4496 	if (window->priv->password != NULL)
4497 		g_string_append (list, window->priv->password);
4498 	g_string_append (list, "\r\n");
4499 	g_string_append (list, (data->op == FR_CLIPBOARD_OP_COPY) ? "copy" : "cut");
4500 	g_string_append (list, "\r\n");
4501 	g_string_append (list, data->base_dir);
4502 	g_string_append (list, "\r\n");
4503 	for (scan = data->files; scan; scan = scan->next) {
4504 		g_string_append (list, scan->data);
4505 		g_string_append (list, "\r\n");
4506 	}
4507 
4508 	return g_string_free (list, FALSE);
4509 }
4510 
4511 
4512 /* --  wait_dnd_extraction -- */
4513 
4514 
4515 typedef struct {
4516 	FrWindow *window;
4517 	GMainLoop *loop;
4518 } DndWaitInfo;
4519 
4520 
4521 static gboolean
extraction_is_finished(gpointer * data)4522 extraction_is_finished (gpointer *data)
4523 {
4524 	DndWaitInfo *wait_info;
4525 	wait_info = (DndWaitInfo *) data;
4526 
4527 	return wait_info->window->priv->dnd_extract_is_running;
4528 }
4529 
4530 
4531 static void
notify_extraction_finished(gpointer * data)4532 notify_extraction_finished (gpointer *data)
4533 {
4534 	DndWaitInfo *wait_info;
4535 	wait_info = (DndWaitInfo *) data;
4536 
4537 	if (g_main_loop_is_running (wait_info->loop))
4538 		g_main_loop_quit (wait_info->loop);
4539 }
4540 
4541 
4542 static void
wait_dnd_extraction(FrWindow * window)4543 wait_dnd_extraction (FrWindow *window)
4544 {
4545 	window->priv->dnd_extract_is_running = TRUE;
4546 	window->priv->dnd_extract_finished_with_error = FALSE;
4547 	fr_window_archive_extract (window,
4548 				   window->priv->drag_file_list,
4549 				   window->priv->drag_destination_folder,
4550 				   window->priv->drag_base_dir,
4551 				   FALSE,
4552 				   FR_OVERWRITE_ASK,
4553 				   FALSE,
4554 				   FALSE);
4555 
4556 	DndWaitInfo wait_info = { NULL, NULL };
4557 	wait_info.loop = g_main_loop_new (NULL, FALSE);
4558 	wait_info.window = window;
4559 	g_timeout_add_full (G_PRIORITY_DEFAULT,
4560 			    500,
4561 			    (GSourceFunc) extraction_is_finished,
4562 			    &wait_info,
4563 			    (GDestroyNotify) notify_extraction_finished);
4564 
4565 	g_main_loop_run (wait_info.loop);
4566 
4567 	g_main_loop_unref (wait_info.loop);
4568 	wait_info.loop = NULL;
4569 	wait_info.window = NULL;
4570 	window->priv->dnd_extract_is_running = FALSE;
4571 }
4572 
4573 
4574 static gboolean
fr_window_folder_tree_drag_data_get(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * selection_data,guint info,guint time,gpointer user_data)4575 fr_window_folder_tree_drag_data_get (GtkWidget        *widget,
4576 				     GdkDragContext   *context,
4577 				     GtkSelectionData *selection_data,
4578 				     guint             info,
4579 				     guint             time,
4580 				     gpointer          user_data)
4581 {
4582 	FrWindow *window = user_data;
4583 	GList    *file_list;
4584 	char     *uri;
4585 	GFile    *destination;
4586 	GFile    *destination_folder;
4587 	char     *xds_response;
4588 
4589 	debug (DEBUG_INFO, "::DragDataGet -->\n");
4590 
4591 	if (window->priv->activity_ref > 0)
4592 		return FALSE;
4593 
4594 	file_list = fr_window_get_folder_tree_selection (window, TRUE, NULL);
4595 	if (file_list == NULL)
4596 		return FALSE;
4597 
4598 	if (gtk_selection_data_get_target (selection_data) == XFR_ATOM) {
4599 		FrClipboardData *tmp;
4600 		char            *data;
4601 
4602 		tmp = fr_clipboard_data_new ();
4603 		tmp->files = file_list;
4604 		tmp->op = FR_CLIPBOARD_OP_COPY;
4605 		tmp->base_dir = g_strdup (fr_window_get_current_location (window));
4606 
4607 		data = get_selection_data_from_clipboard_data (window, tmp);
4608 		gtk_selection_data_set (selection_data, XFR_ATOM, 8, (guchar *) data, strlen (data));
4609 
4610 		fr_clipboard_data_unref (tmp);
4611 		g_free (data);
4612 
4613 		return TRUE;
4614 	}
4615 
4616 	if (! nautilus_xds_dnd_is_valid_xds_context (context))
4617 		return FALSE;
4618 
4619 	uri  = get_xds_atom_value (context);
4620 	g_return_val_if_fail (uri != NULL, FALSE);
4621 
4622 	destination = g_file_new_for_uri (uri);
4623 	destination_folder = g_file_get_parent (destination);
4624 
4625 	g_object_unref (destination);
4626 	g_free (uri);
4627 
4628 	/* check whether the extraction can be performed in the destination
4629 	 * folder */
4630 
4631 	g_clear_error (&window->priv->drag_error);
4632 
4633 	if (! _g_file_check_permissions (destination_folder, R_OK | W_OK)) {
4634 		char *display_name;
4635 
4636 		display_name = _g_file_get_display_basename (destination_folder);
4637 		window->priv->drag_error = g_error_new (FR_ERROR, 0, _("You don’t have the right permissions to extract archives in the folder “%s”"), display_name);
4638 
4639 		g_free (display_name);
4640 	}
4641 
4642 	if (window->priv->drag_error == NULL) {
4643 		char *selected_folder;
4644 
4645 		_g_object_unref (window->priv->drag_destination_folder);
4646 		g_free (window->priv->drag_base_dir);
4647 		_g_string_list_free (window->priv->drag_file_list);
4648 		window->priv->drag_destination_folder = g_object_ref (destination_folder);
4649 		selected_folder = fr_window_get_selected_folder_in_tree_view (window);
4650 		window->priv->drag_base_dir = _g_path_remove_level (selected_folder);
4651 		window->priv->drag_file_list = file_list;
4652 
4653 		wait_dnd_extraction (window);
4654 
4655 		g_free (selected_folder);
4656 	}
4657 
4658 	g_object_unref (destination_folder);
4659 
4660 	/* sends back the response */
4661 
4662 	xds_response = ((window->priv->drag_error == NULL && !window->priv->dnd_extract_finished_with_error) ? "S" : "E");
4663 	gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) xds_response, 1);
4664 
4665 	window->priv->dnd_extract_finished_with_error = FALSE;
4666 
4667 	debug (DEBUG_INFO, "::DragDataGet <--\n");
4668 
4669 	return TRUE;
4670 }
4671 
4672 
4673 gboolean
fr_window_file_list_drag_data_get(FrWindow * window,GdkDragContext * context,GtkSelectionData * selection_data,GList * path_list)4674 fr_window_file_list_drag_data_get (FrWindow         *window,
4675 				   GdkDragContext   *context,
4676 				   GtkSelectionData *selection_data,
4677 				   GList            *path_list)
4678 {
4679 	char  *uri;
4680 	char  *xds_response;
4681 	GFile *destination;
4682 	GFile *destination_folder;
4683 
4684 	debug (DEBUG_INFO, "::DragDataGet -->\n");
4685 
4686 	if (window->priv->path_clicked != NULL) {
4687 		gtk_tree_path_free (window->priv->path_clicked);
4688 		window->priv->path_clicked = NULL;
4689 	}
4690 
4691 	if (window->priv->activity_ref > 0)
4692 		return FALSE;
4693 
4694 	if (gtk_selection_data_get_target (selection_data) == XFR_ATOM) {
4695 		FrClipboardData *tmp;
4696 		char            *data;
4697 
4698 		tmp = fr_clipboard_data_new ();
4699 		tmp->files = fr_window_get_file_list_selection (window, TRUE, NULL);
4700 		tmp->op = FR_CLIPBOARD_OP_COPY;
4701 		tmp->base_dir = g_strdup (fr_window_get_current_location (window));
4702 
4703 		data = get_selection_data_from_clipboard_data (window, tmp);
4704 		gtk_selection_data_set (selection_data, XFR_ATOM, 8, (guchar *) data, strlen (data));
4705 
4706 		fr_clipboard_data_unref (tmp);
4707 		g_free (data);
4708 
4709 		return TRUE;
4710 	}
4711 
4712 	if (! nautilus_xds_dnd_is_valid_xds_context (context))
4713 		return FALSE;
4714 
4715 	uri = get_xds_atom_value (context);
4716 	g_return_val_if_fail (uri != NULL, FALSE);
4717 
4718 	destination = g_file_new_for_uri (uri);
4719 	g_free (uri);
4720 
4721 	if (destination == NULL)
4722 		return FALSE;
4723 
4724 	destination_folder = g_file_get_parent (destination);
4725 	g_object_unref (destination);
4726 
4727 	if (destination_folder == NULL)
4728 		return FALSE;
4729 
4730 	/* check whether the extraction can be performed in the destination
4731 	 * folder */
4732 
4733 	g_clear_error (&window->priv->drag_error);
4734 
4735 	if (! _g_file_check_permissions (destination_folder, R_OK | W_OK)) {
4736 		char *display_name;
4737 
4738 		display_name = _g_file_get_display_basename (destination_folder);
4739 		window->priv->drag_error = g_error_new (FR_ERROR, 0, _("You don’t have the right permissions to extract archives in the folder “%s”"), display_name);
4740 
4741 		g_free (display_name);
4742 	}
4743 
4744 	if (window->priv->drag_error == NULL) {
4745 		_g_object_unref (window->priv->drag_destination_folder);
4746 		g_free (window->priv->drag_base_dir);
4747 		_g_string_list_free (window->priv->drag_file_list);
4748 		window->priv->drag_destination_folder = g_object_ref (destination_folder);
4749 		window->priv->drag_base_dir = g_strdup (fr_window_get_current_location (window));
4750 		window->priv->drag_file_list = fr_window_get_file_list_from_path_list (window, path_list, NULL);
4751 
4752 		wait_dnd_extraction (window);
4753 	}
4754 
4755 	g_object_unref (destination_folder);
4756 
4757 	/* sends back the response */
4758 
4759 	xds_response = ((window->priv->drag_error == NULL && !window->priv->dnd_extract_finished_with_error) ? "S" : "E");
4760 	gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (guchar *) xds_response, 1);
4761 
4762 	window->priv->dnd_extract_finished_with_error = FALSE;
4763 
4764 	debug (DEBUG_INFO, "::DragDataGet <--\n");
4765 
4766 	return TRUE;
4767 }
4768 
4769 
4770 /* -- window_new -- */
4771 
4772 
4773 static void
fr_window_update_columns_visibility(FrWindow * window)4774 fr_window_update_columns_visibility (FrWindow *window)
4775 {
4776 	GtkTreeView       *tree_view = GTK_TREE_VIEW (window->priv->list_view);
4777 	GtkTreeViewColumn *column;
4778 
4779 	column = gtk_tree_view_get_column (tree_view, 1);
4780 	gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_SIZE));
4781 
4782 	column = gtk_tree_view_get_column (tree_view, 2);
4783 	gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_TYPE));
4784 
4785 	column = gtk_tree_view_get_column (tree_view, 3);
4786 	gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_TIME));
4787 
4788 	column = gtk_tree_view_get_column (tree_view, 4);
4789 	gtk_tree_view_column_set_visible (column, g_settings_get_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH));
4790 }
4791 
4792 
4793 static gboolean
key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)4794 key_press_cb (GtkWidget   *widget,
4795 	      GdkEventKey *event,
4796 	      gpointer     data)
4797 {
4798 	FrWindow *window = data;
4799 	gboolean  retval = FALSE;
4800 	gboolean  alt;
4801 
4802 	if (gtk_widget_has_focus (window->priv->location_entry))
4803 		return FALSE;
4804 
4805 	if (gtk_widget_has_focus (window->priv->filter_entry)) {
4806 		switch (event->keyval) {
4807 		case GDK_KEY_Escape:
4808 			fr_window_deactivate_filter (window);
4809 			retval = TRUE;
4810 			break;
4811 		default:
4812 			break;
4813 		}
4814 		return retval;
4815 	}
4816 
4817 	alt = (event->state & GDK_MOD1_MASK) == GDK_MOD1_MASK;
4818 
4819 	switch (event->keyval) {
4820 	case GDK_KEY_Escape:
4821 		fr_window_stop (window);
4822 		if (window->priv->filter_mode)
4823 			fr_window_deactivate_filter (window);
4824 		retval = TRUE;
4825 		break;
4826 
4827 	case GDK_KEY_F10:
4828 		if (event->state & GDK_SHIFT_MASK) {
4829 			GtkTreeSelection *selection;
4830 
4831 			selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
4832 			if (selection == NULL)
4833 				return FALSE;
4834 
4835 			gtk_menu_popup_at_pointer (GTK_MENU (window->priv->file_popup_menu), (GdkEvent *) event);
4836 			retval = TRUE;
4837 		}
4838 		break;
4839 
4840 	case GDK_KEY_Up:
4841 	case GDK_KEY_KP_Up:
4842 		if (alt) {
4843 			fr_window_go_up_one_level (window);
4844 			retval = TRUE;
4845 		}
4846 		break;
4847 
4848 	case GDK_KEY_BackSpace:
4849 		fr_window_go_up_one_level (window);
4850 		retval = TRUE;
4851 		break;
4852 
4853 	case GDK_KEY_Right:
4854 	case GDK_KEY_KP_Right:
4855 		if (alt) {
4856 			fr_window_go_forward (window);
4857 			retval = TRUE;
4858 		}
4859 		break;
4860 
4861 	case GDK_KEY_Left:
4862 	case GDK_KEY_KP_Left:
4863 		if (alt) {
4864 			fr_window_go_back (window);
4865 			retval = TRUE;
4866 		}
4867 		break;
4868 
4869 	case GDK_KEY_Home:
4870 	case GDK_KEY_KP_Home:
4871 		if (alt) {
4872 			fr_window_go_to_location (window, "/", FALSE);
4873 			retval = TRUE;
4874 		}
4875 		break;
4876 
4877 	case GDK_KEY_Delete:
4878 		if (! gtk_widget_has_focus (window->priv->filter_entry)) {
4879 			fr_window_activate_delete (NULL, NULL, window);
4880 			retval = TRUE;
4881 		}
4882 		break;
4883 
4884 	default:
4885 		break;
4886 	}
4887 
4888 	return retval;
4889 }
4890 
4891 
4892 static gboolean
dir_tree_selection_changed_cb(GtkTreeSelection * selection,gpointer user_data)4893 dir_tree_selection_changed_cb (GtkTreeSelection *selection,
4894 			       gpointer          user_data)
4895 {
4896 	FrWindow    *window = user_data;
4897 	GtkTreeIter  iter;
4898 
4899 	if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
4900 		char *path;
4901 
4902 		gtk_tree_model_get (GTK_TREE_MODEL (window->priv->tree_store),
4903 				    &iter,
4904 				    TREE_COLUMN_PATH, &path,
4905 				    -1);
4906 		fr_window_go_to_location (window, path, FALSE);
4907 		g_free (path);
4908 	}
4909 
4910 	return FALSE;
4911 }
4912 
4913 
4914 static gboolean
selection_changed_cb(GtkTreeSelection * selection,gpointer user_data)4915 selection_changed_cb (GtkTreeSelection *selection,
4916 		      gpointer          user_data)
4917 {
4918 	FrWindow *window = user_data;
4919 
4920 	fr_window_update_sensitivity (window);
4921 
4922 	return FALSE;
4923 }
4924 
4925 
4926 static gboolean
fr_window_delete_event_cb(GtkWidget * caller,GdkEvent * event,FrWindow * window)4927 fr_window_delete_event_cb (GtkWidget *caller,
4928 			   GdkEvent  *event,
4929 			   FrWindow  *window)
4930 {
4931 	fr_window_close (window);
4932 	return TRUE;
4933 }
4934 
4935 
4936 static gboolean
is_single_click_policy(FrWindow * window)4937 is_single_click_policy (FrWindow *window)
4938 {
4939 	char     *value;
4940 	gboolean  result;
4941 
4942 	if (window->priv->settings_nautilus == NULL)
4943 		return FALSE;
4944 
4945 	value = g_settings_get_string (window->priv->settings_nautilus, NAUTILUS_CLICK_POLICY);
4946 	result = (value != NULL) && (strncmp (value, "single", 6) == 0);
4947 	g_free (value);
4948 
4949 	return result;
4950 }
4951 
4952 
4953 static void
filename_cell_data_func(GtkTreeViewColumn * column,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,FrWindow * window)4954 filename_cell_data_func (GtkTreeViewColumn *column,
4955 			 GtkCellRenderer   *renderer,
4956 			 GtkTreeModel      *model,
4957 			 GtkTreeIter       *iter,
4958 			 FrWindow          *window)
4959 {
4960 	char           *text;
4961 	GtkTreePath    *path;
4962 	PangoUnderline  underline;
4963 
4964 	gtk_tree_model_get (model, iter,
4965 			    COLUMN_NAME, &text,
4966 			    -1);
4967 
4968 	if (window->priv->single_click) {
4969 		path = gtk_tree_model_get_path (model, iter);
4970 
4971 		if ((window->priv->list_hover_path == NULL)
4972 		    || gtk_tree_path_compare (path, window->priv->list_hover_path))
4973 			underline = PANGO_UNDERLINE_NONE;
4974 		else
4975 			underline = PANGO_UNDERLINE_SINGLE;
4976 
4977 		gtk_tree_path_free (path);
4978 	}
4979 	else
4980 		underline = PANGO_UNDERLINE_NONE;
4981 
4982 	g_object_set (G_OBJECT (renderer),
4983 		      "text", text,
4984 		      "underline", underline,
4985 		      NULL);
4986 
4987 	g_free (text);
4988 }
4989 
4990 
4991 static void
add_dir_tree_columns(FrWindow * window,GtkTreeView * treeview)4992 add_dir_tree_columns (FrWindow    *window,
4993 		      GtkTreeView *treeview)
4994 {
4995 	GtkCellRenderer   *renderer;
4996 	GtkTreeViewColumn *column;
4997 	GValue             value = { 0, };
4998 
4999 	/* First column. */
5000 
5001 	column = gtk_tree_view_column_new ();
5002 	gtk_tree_view_column_set_title (column, _("Folders"));
5003 
5004 	/* icon */
5005 
5006 	renderer = gtk_cell_renderer_pixbuf_new ();
5007 	gtk_tree_view_column_pack_start (column, renderer, FALSE);
5008 	gtk_tree_view_column_set_attributes (column, renderer,
5009 					     "pixbuf", TREE_COLUMN_ICON,
5010 					     NULL);
5011 
5012 	/* name */
5013 
5014 	renderer = gtk_cell_renderer_text_new ();
5015 
5016 	g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
5017 	g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
5018 	g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
5019 	g_value_unset (&value);
5020 
5021 	gtk_tree_view_column_pack_start (column,
5022 					 renderer,
5023 					 TRUE);
5024 	gtk_tree_view_column_set_attributes (column, renderer,
5025 					     "text", TREE_COLUMN_NAME,
5026 					     "weight", TREE_COLUMN_WEIGHT,
5027 					     NULL);
5028 
5029 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
5030 	gtk_tree_view_column_set_sort_column_id (column, TREE_COLUMN_NAME);
5031 
5032 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
5033 }
5034 
5035 
5036 static void
add_file_list_columns(FrWindow * window,GtkTreeView * treeview)5037 add_file_list_columns (FrWindow    *window,
5038 		       GtkTreeView *treeview)
5039 {
5040 	static char       *titles[] = {NC_("File", "Size"),
5041 				       NC_("File", "Type"),
5042 				       NC_("File", "Modified"),
5043 				       NC_("File", "Location")};
5044 	GtkCellRenderer   *renderer;
5045 	GtkTreeViewColumn *column;
5046 	GValue             value = { 0, };
5047 	int                i, j, w;
5048 
5049 	/* First column. */
5050 
5051 	window->priv->filename_column = column = gtk_tree_view_column_new ();
5052 	gtk_tree_view_column_set_title (column, C_("File", "Name"));
5053 
5054 	/* emblem */
5055 
5056 	renderer = gtk_cell_renderer_pixbuf_new ();
5057 	gtk_tree_view_column_pack_end (column, renderer, FALSE);
5058 	gtk_tree_view_column_set_attributes (column, renderer,
5059 					     "pixbuf", COLUMN_EMBLEM,
5060 					     NULL);
5061 
5062 	/* icon */
5063 
5064 	renderer = gtk_cell_renderer_pixbuf_new ();
5065 	gtk_tree_view_column_pack_start (column, renderer, FALSE);
5066 	gtk_tree_view_column_set_attributes (column, renderer,
5067 					     "pixbuf", COLUMN_ICON,
5068 					     NULL);
5069 
5070 	/* name */
5071 
5072 	window->priv->single_click = is_single_click_policy (window);
5073 
5074 	renderer = gtk_cell_renderer_text_new ();
5075 
5076 	g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
5077 	g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
5078 	g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
5079 	g_value_unset (&value);
5080 
5081 	gtk_tree_view_column_pack_start (column,
5082 					 renderer,
5083 					 TRUE);
5084 	gtk_tree_view_column_set_attributes (column, renderer,
5085 					     "text", COLUMN_NAME,
5086 					     NULL);
5087 
5088 	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
5089 	w = g_settings_get_int (window->priv->settings_listing, PREF_LISTING_NAME_COLUMN_WIDTH);
5090 	if (w <= 0)
5091 		w = DEFAULT_NAME_COLUMN_WIDTH;
5092 	gtk_tree_view_column_set_fixed_width (column, w);
5093 	gtk_tree_view_column_set_resizable (column, TRUE);
5094 	gtk_tree_view_column_set_sort_column_id (column, FR_WINDOW_SORT_BY_NAME);
5095 	gtk_tree_view_column_set_cell_data_func (column, renderer,
5096 						 (GtkTreeCellDataFunc) filename_cell_data_func,
5097 						 window, NULL);
5098 
5099 	gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
5100 
5101 	/* Other columns */
5102 
5103 	for (j = 0, i = COLUMN_SIZE; i < NUMBER_OF_COLUMNS; i++, j++) {
5104 		GValue  value = { 0, };
5105 
5106 		renderer = gtk_cell_renderer_text_new ();
5107 		column = gtk_tree_view_column_new_with_attributes (g_dpgettext2 (NULL, "File", titles[j]),
5108 								   renderer,
5109 								   "text", i,
5110 								   NULL);
5111 
5112 		gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
5113 		gtk_tree_view_column_set_fixed_width (column, OTHER_COLUMNS_WIDTH);
5114 		gtk_tree_view_column_set_resizable (column, TRUE);
5115 
5116 		gtk_tree_view_column_set_sort_column_id (column, FR_WINDOW_SORT_BY_NAME + 1 + j);
5117 
5118 		g_value_init (&value, PANGO_TYPE_ELLIPSIZE_MODE);
5119 		g_value_set_enum (&value, PANGO_ELLIPSIZE_END);
5120 		g_object_set_property (G_OBJECT (renderer), "ellipsize", &value);
5121 		g_value_unset (&value);
5122 
5123 		gtk_tree_view_append_column (treeview, column);
5124 	}
5125 }
5126 
5127 
5128 static int
name_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5129 name_column_sort_func (GtkTreeModel *model,
5130 		       GtkTreeIter  *a,
5131 		       GtkTreeIter  *b,
5132 		       gpointer      user_data)
5133 {
5134 	FileData    *fdata1;
5135 	FileData    *fdata2;
5136 	GtkSortType  sort_order;
5137 	int          result;
5138 
5139 	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5140 
5141 	gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5142 	gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5143 
5144 	if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5145 		result = strcmp (fdata1->sort_key, fdata2->sort_key);
5146 	}
5147 	else {
5148         	result = file_data_is_dir (fdata1) ? -1 : 1;
5149         	if (sort_order == GTK_SORT_DESCENDING)
5150         		result = -1 * result;
5151 	}
5152 
5153 	return result;
5154 }
5155 
5156 
5157 static int
size_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5158 size_column_sort_func (GtkTreeModel *model,
5159 		       GtkTreeIter  *a,
5160 		       GtkTreeIter  *b,
5161 		       gpointer      user_data)
5162 {
5163 	FileData    *fdata1;
5164 	FileData    *fdata2;
5165 	GtkSortType  sort_order;
5166 	int          result;
5167 	goffset      size_difference;
5168 
5169 	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5170 
5171 	gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5172 	gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5173 
5174 	if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5175         	if (file_data_is_dir (fdata1))
5176 			size_difference = fdata1->dir_size - fdata2->dir_size;
5177         	else
5178 			size_difference = fdata1->size - fdata2->size;
5179 		result = (size_difference > 0) - (size_difference < 0);
5180         }
5181         else {
5182         	result = file_data_is_dir (fdata1) ? -1 : 1;
5183         	if (sort_order == GTK_SORT_DESCENDING)
5184         		result = -1 * result;
5185         }
5186 
5187 	return result;
5188 }
5189 
5190 
5191 static int
type_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5192 type_column_sort_func (GtkTreeModel *model,
5193 		       GtkTreeIter  *a,
5194 		       GtkTreeIter  *b,
5195 		       gpointer      user_data)
5196 {
5197 	FileData    *fdata1;
5198 	FileData    *fdata2;
5199 	GtkSortType  sort_order;
5200 	int          result;
5201 
5202 	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5203 
5204 	gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5205 	gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5206 
5207 	if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5208         	if (file_data_is_dir (fdata1)) {
5209                 	result = strcmp (fdata1->sort_key, fdata2->sort_key);
5210                 	if (sort_order == GTK_SORT_DESCENDING)
5211                 		result = -1 * result;
5212         	}
5213         	else {
5214         		const char  *desc1, *desc2;
5215 
5216         		desc1 = g_content_type_get_description (fdata1->content_type);
5217         		desc2 = g_content_type_get_description (fdata2->content_type);
5218         		result = strcasecmp (desc1, desc2);
5219         		if (result == 0)
5220         			result = strcmp (fdata1->sort_key, fdata2->sort_key);
5221         	}
5222         }
5223         else {
5224         	result = file_data_is_dir (fdata1) ? -1 : 1;
5225         	if (sort_order == GTK_SORT_DESCENDING)
5226         		result = -1 * result;
5227         }
5228 
5229 	return result;
5230 }
5231 
5232 
5233 static int
time_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5234 time_column_sort_func (GtkTreeModel *model,
5235 		       GtkTreeIter  *a,
5236 		       GtkTreeIter  *b,
5237 		       gpointer      user_data)
5238 {
5239 	FileData    *fdata1;
5240 	FileData    *fdata2;
5241 	GtkSortType  sort_order;
5242 	int          result;
5243 
5244 	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), NULL, &sort_order);
5245 
5246 	gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, -1);
5247 	gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, -1);
5248 
5249 	if (file_data_is_dir (fdata1) == file_data_is_dir (fdata2)) {
5250         	if (file_data_is_dir (fdata1)) {
5251                 	result = strcmp (fdata1->sort_key, fdata2->sort_key);
5252                 	if (sort_order == GTK_SORT_DESCENDING)
5253                 		result = -1 * result;
5254         	}
5255         	else
5256         		result = fdata1->modified - fdata2->modified;
5257         }
5258         else {
5259         	result = file_data_is_dir (fdata1) ? -1 : 1;
5260         	if (sort_order == GTK_SORT_DESCENDING)
5261         		result = -1 * result;
5262         }
5263 
5264 	return result;
5265 }
5266 
5267 
5268 static int
path_column_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)5269 path_column_sort_func (GtkTreeModel *model,
5270 		       GtkTreeIter  *a,
5271 		       GtkTreeIter  *b,
5272 		       gpointer      user_data)
5273 {
5274 	FileData *fdata1;
5275 	FileData *fdata2;
5276 	char     *path1;
5277 	char     *path2;
5278 	int       result;
5279 
5280 	gtk_tree_model_get (model, a, COLUMN_FILE_DATA, &fdata1, COLUMN_PATH, &path1, -1);
5281 	gtk_tree_model_get (model, b, COLUMN_FILE_DATA, &fdata2, COLUMN_PATH, &path2, -1);
5282 
5283 	result = strcmp (path1, path2);
5284 	if (result == 0)
5285 		result = strcmp (fdata1->sort_key, fdata2->sort_key);
5286 
5287 	g_free (path1);
5288 	g_free (path2);
5289 
5290 	return result;
5291 }
5292 
5293 
5294 static gboolean
fr_window_show_cb(GtkWidget * widget,FrWindow * window)5295 fr_window_show_cb (GtkWidget *widget,
5296 		   FrWindow  *window)
5297 {
5298 	fr_window_update_current_location (window);
5299 
5300 	window->priv->view_sidebar = g_settings_get_boolean (window->priv->settings_ui, PREF_UI_VIEW_SIDEBAR);
5301 	fr_window_set_action_state (window, "view-sidebar", window->priv->view_sidebar);
5302 
5303 	gtk_widget_hide (window->priv->filter_bar);
5304 
5305 	return TRUE;
5306 }
5307 
5308 
5309 /* preferences changes notification callbacks */
5310 
5311 
5312 static void
pref_view_folders_changed(GSettings * settings,const char * key,gpointer user_data)5313 pref_view_folders_changed (GSettings  *settings,
5314 		  	   const char *key,
5315 		  	   gpointer    user_data)
5316 {
5317 	FrWindow *window = user_data;
5318 
5319 	fr_window_set_folders_visibility (window, g_settings_get_boolean (settings, key));
5320 }
5321 
5322 
5323 static void
pref_show_field_changed(GSettings * settings,const char * key,gpointer user_data)5324 pref_show_field_changed (GSettings  *settings,
5325 		  	 const char *key,
5326 		  	 gpointer    user_data)
5327 {
5328 	FrWindow *window = user_data;
5329 
5330 	fr_window_update_columns_visibility (window);
5331 }
5332 
5333 
5334 static void
pref_list_mode_changed(GSettings * settings,const char * key,gpointer user_data)5335 pref_list_mode_changed (GSettings  *settings,
5336 			const char *key,
5337 			gpointer    user_data)
5338 {
5339 	FrWindow *window = user_data;
5340 
5341 	fr_window_set_list_mode (window, g_settings_get_enum (settings, key));
5342 }
5343 
5344 
5345 static void
pref_click_policy_changed(GSettings * settings,const char * key,gpointer user_data)5346 pref_click_policy_changed (GSettings  *settings,
5347 		  	   const char *key,
5348 		  	   gpointer    user_data)
5349 {
5350 	FrWindow   *window = user_data;
5351 	GdkWindow  *win = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (window->priv->list_view));
5352 	GdkDisplay *display;
5353 
5354 	window->priv->single_click = is_single_click_policy (window);
5355 
5356 	gdk_window_set_cursor (win, NULL);
5357 	display = gtk_widget_get_display (GTK_WIDGET (window->priv->list_view));
5358 	if (display != NULL)
5359 		gdk_display_flush (display);
5360 }
5361 
5362 
5363 static void
theme_changed_cb(GtkIconTheme * theme,FrWindow * window)5364 theme_changed_cb (GtkIconTheme *theme,
5365 		  FrWindow     *window)
5366 {
5367 	if (window->priv->populating_file_list)
5368 		return;
5369 
5370 	gth_icon_cache_clear (window->priv->list_icon_cache);
5371 	gth_icon_cache_clear (window->priv->tree_icon_cache);
5372 
5373 	fr_window_update_file_list (window, TRUE);
5374 	fr_window_update_dir_tree (window);
5375 }
5376 
5377 
5378 static gboolean
fr_archive_stoppable_cb(FrArchive * archive,gboolean stoppable,FrWindow * window)5379 fr_archive_stoppable_cb (FrArchive *archive,
5380 			 gboolean   stoppable,
5381 			 FrWindow  *window)
5382 {
5383 	window->priv->stoppable = stoppable;
5384 	if (window->priv->progress_dialog != NULL)
5385 		gtk_dialog_set_response_sensitive (GTK_DIALOG (window->priv->progress_dialog),
5386 						   GTK_RESPONSE_OK,
5387 						   stoppable);
5388 	return TRUE;
5389 }
5390 
5391 
5392 static void
fr_window_activate_filter(FrWindow * window)5393 fr_window_activate_filter (FrWindow *window)
5394 {
5395 	GtkTreeView       *tree_view = GTK_TREE_VIEW (window->priv->list_view);
5396 	GtkTreeViewColumn *column;
5397 
5398 	gtk_widget_show (window->priv->filter_bar);
5399 	window->priv->list_mode = FR_WINDOW_LIST_MODE_FLAT;
5400 
5401 	gtk_list_store_clear (window->priv->list_store);
5402 
5403 	column = gtk_tree_view_get_column (tree_view, 4);
5404 	gtk_tree_view_column_set_visible (column, TRUE);
5405 
5406 	fr_window_update_file_list (window, TRUE);
5407 	fr_window_update_dir_tree (window);
5408 	fr_window_update_current_location (window);
5409 }
5410 
5411 
5412 static void
filter_entry_search_changed_cb(GtkEntry * entry,FrWindow * window)5413 filter_entry_search_changed_cb (GtkEntry *entry,
5414 				FrWindow *window)
5415 {
5416 	fr_window_activate_filter (window);
5417 }
5418 
5419 
5420 static void
fr_window_attach(FrWindow * window,GtkWidget * child,FrWindowArea area)5421 fr_window_attach (FrWindow      *window,
5422 		  GtkWidget     *child,
5423 		  FrWindowArea   area)
5424 {
5425 	int position;
5426 
5427 	g_return_if_fail (window != NULL);
5428 	g_return_if_fail (FR_IS_WINDOW (window));
5429 	g_return_if_fail (child != NULL);
5430 	g_return_if_fail (GTK_IS_WIDGET (child));
5431 
5432 	switch (area) {
5433 	case FR_WINDOW_AREA_MENUBAR:
5434 		position = 0;
5435 		break;
5436 	case FR_WINDOW_AREA_TOOLBAR:
5437 		position = 1;
5438 		break;
5439 	case FR_WINDOW_AREA_LOCATIONBAR:
5440 		position = 2;
5441 		break;
5442 	case FR_WINDOW_AREA_FILTERBAR:
5443 		position = 3;
5444 		break;
5445 	case FR_WINDOW_AREA_CONTENTS:
5446 		position = 4;
5447 		if (window->priv->contents != NULL)
5448 			gtk_widget_destroy (window->priv->contents);
5449 		window->priv->contents = child;
5450 		gtk_widget_set_vexpand (child, TRUE);
5451 		break;
5452 	case FR_WINDOW_AREA_STATUSBAR:
5453 		position = 5;
5454 		break;
5455 	default:
5456 		g_critical ("%s: area not recognized!", G_STRFUNC);
5457 		return;
5458 		break;
5459 	}
5460 
5461 	gtk_widget_set_hexpand (child, TRUE);
5462 	gtk_grid_attach (GTK_GRID (window->priv->layout),
5463 			 child,
5464 			 0, position,
5465 			 1, 1);
5466 }
5467 
5468 
5469 /* -- fr_window_add_accelerators -- */
5470 
5471 
5472 static GtkAccelGroup *
gth_window_get_accel_group(FrWindow * window)5473 gth_window_get_accel_group (FrWindow *window)
5474 {
5475 	if (window->priv->accel_group == NULL) {
5476 		window->priv->accel_group = gtk_accel_group_new ();
5477 		gtk_window_add_accel_group (GTK_WINDOW (window), window->priv->accel_group);
5478 	}
5479 
5480 	return window->priv->accel_group;
5481 }
5482 
5483 
5484 static void
fr_window_add_accelerators(FrWindow * window,const FrAccelerator * accelerators,int n_accelerators)5485 fr_window_add_accelerators (FrWindow                 *window,
5486 			    const FrAccelerator      *accelerators,
5487 			    int                       n_accelerators)
5488 {
5489 	GtkAccelGroup *accel_group;
5490 	int            i;
5491 
5492 	accel_group = gth_window_get_accel_group (window);
5493 	for (i = 0; i < n_accelerators; i++) {
5494 		const FrAccelerator *acc = accelerators + i;
5495 
5496 		_gtk_window_add_accelerator_for_action (GTK_WINDOW (window),
5497 						        accel_group,
5498 						        acc->action_name,
5499 						        acc->accelerator,
5500 						        NULL);
5501 	}
5502 }
5503 
5504 
5505 static void
fr_window_construct(FrWindow * window)5506 fr_window_construct (FrWindow *window)
5507 {
5508 	GtkWidget          *list_scrolled_window;
5509 	GtkWidget          *navigation_commands;
5510 	GtkWidget          *location_bar_content;
5511 	GtkWidget          *location_box;
5512 	GtkWidget          *filter_box;
5513 	GtkWidget          *tree_scrolled_window;
5514 	GtkWidget          *button;
5515 	GtkTreeSelection   *selection;
5516 	GtkSizeGroup       *header_bar_size_group;
5517 
5518 	/* Create the settings objects */
5519 
5520 	window->priv->settings_listing = g_settings_new (FILE_ROLLER_SCHEMA_LISTING);
5521 	window->priv->settings_ui = g_settings_new (FILE_ROLLER_SCHEMA_UI);
5522 	window->priv->settings_general = g_settings_new (FILE_ROLLER_SCHEMA_GENERAL);
5523 	window->priv->settings_dialogs = g_settings_new (FILE_ROLLER_SCHEMA_DIALOGS);
5524 	window->priv->settings_nautilus = _g_settings_new_if_schema_installed (NAUTILUS_SCHEMA);
5525 
5526 	/* Create the application. */
5527 
5528 	window->priv->layout = gtk_grid_new ();
5529 	gtk_container_add (GTK_CONTAINER (window), window->priv->layout);
5530 	gtk_widget_show (window->priv->layout);
5531 
5532 	gtk_window_set_title (GTK_WINDOW (window), _("Archive Manager"));
5533 
5534 	g_signal_connect (G_OBJECT (window),
5535 			  "delete_event",
5536 			  G_CALLBACK (fr_window_delete_event_cb),
5537 			  window);
5538 
5539 	g_signal_connect (G_OBJECT (window),
5540 			  "show",
5541 			  G_CALLBACK (fr_window_show_cb),
5542 			  window);
5543 
5544 	window->priv->theme_changed_handler_id =
5545 		g_signal_connect (gtk_icon_theme_get_default (),
5546 				  "changed",
5547 				  G_CALLBACK (theme_changed_cb),
5548 				  window);
5549 
5550 	gtk_window_set_default_size (GTK_WINDOW (window),
5551 				     g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_WIDTH),
5552 				     g_settings_get_int (window->priv->settings_ui, PREF_UI_WINDOW_HEIGHT));
5553 
5554 	g_signal_connect (G_OBJECT (window),
5555 			  "key_press_event",
5556 			  G_CALLBACK (key_press_cb),
5557 			  window);
5558 
5559 	/* Initialize Data. */
5560 
5561 	window->priv->list_mode = window->priv->last_list_mode = g_settings_get_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE);
5562 	g_settings_set_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT));
5563 
5564 	window->priv->history = NULL;
5565 	window->priv->history_current = NULL;
5566 
5567 	window->priv->action = FR_ACTION_NONE;
5568 
5569 	window->priv->open_default_dir = g_object_ref (_g_file_get_home ());
5570 	window->priv->add_default_dir = NULL;
5571 	window->priv->extract_default_dir = g_object_ref (_g_file_get_home ());
5572 
5573 	window->priv->give_focus_to_the_list = FALSE;
5574 
5575 	window->priv->activity_ref = 0;
5576 	window->priv->activity_timeout_handle = 0;
5577 
5578 	window->priv->archive_present = FALSE;
5579 	window->priv->archive_new = FALSE;
5580 	window->priv->reload_archive = FALSE;
5581 	window->priv->archive_file = NULL;
5582 
5583 	window->priv->drag_destination_folder = NULL;
5584 	window->priv->drag_base_dir = NULL;
5585 	window->priv->drag_error = NULL;
5586 	window->priv->drag_file_list = NULL;
5587 
5588 	window->priv->batch_mode = FALSE;
5589 	window->priv->batch_action_list = NULL;
5590 	window->priv->batch_action = NULL;
5591 
5592 	window->priv->password = NULL;
5593 	window->priv->compression = g_settings_get_enum (window->priv->settings_general, PREF_GENERAL_COMPRESSION_LEVEL);
5594 	window->priv->encrypt_header = g_settings_get_boolean (window->priv->settings_general, PREF_GENERAL_ENCRYPT_HEADER);
5595 	window->priv->volume_size = 0;
5596 
5597 	window->priv->stoppable = TRUE;
5598 
5599 	window->priv->batch_adding_one_file = FALSE;
5600 
5601 	window->priv->path_clicked = NULL;
5602 
5603 	window->priv->current_view_length = 0;
5604 
5605 	window->priv->current_action.type = FR_BATCH_ACTION_NONE;
5606 	window->priv->current_action.data = NULL;
5607 	window->priv->current_action.free_func = NULL;
5608 
5609 	window->priv->pd_last_archive = NULL;
5610 	window->priv->pd_last_message = NULL;
5611 	window->priv->pd_last_fraction = 0.0;
5612 
5613 	/* Create the widgets. */
5614 
5615 	/* * File list. */
5616 
5617 	window->priv->list_store = fr_list_model_new (NUMBER_OF_COLUMNS,
5618 						      G_TYPE_POINTER,
5619 						      GDK_TYPE_PIXBUF,
5620 						      G_TYPE_STRING,
5621 						      GDK_TYPE_PIXBUF,
5622 						      G_TYPE_STRING,
5623 						      G_TYPE_STRING,
5624 						      G_TYPE_STRING,
5625 						      G_TYPE_STRING);
5626 	g_object_set_data (G_OBJECT (window->priv->list_store), "FrWindow", window);
5627 	window->priv->list_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->list_store));
5628 
5629 	add_file_list_columns (window, GTK_TREE_VIEW (window->priv->list_view));
5630 	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (window->priv->list_view),
5631 					 TRUE);
5632 	gtk_tree_view_set_search_column (GTK_TREE_VIEW (window->priv->list_view),
5633 					 COLUMN_NAME);
5634 
5635 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5636 					 FR_WINDOW_SORT_BY_NAME, name_column_sort_func,
5637 					 NULL, NULL);
5638 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5639 					 FR_WINDOW_SORT_BY_SIZE, size_column_sort_func,
5640 					 NULL, NULL);
5641 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5642 					 FR_WINDOW_SORT_BY_TYPE, type_column_sort_func,
5643 					 NULL, NULL);
5644 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5645 					 FR_WINDOW_SORT_BY_TIME, time_column_sort_func,
5646 					 NULL, NULL);
5647 	gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (window->priv->list_store),
5648 					 FR_WINDOW_SORT_BY_PATH, path_column_sort_func,
5649 					 NULL, NULL);
5650 
5651 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view));
5652 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
5653 
5654 	g_signal_connect (selection,
5655 			  "changed",
5656 			  G_CALLBACK (selection_changed_cb),
5657 			  window);
5658 	g_signal_connect (G_OBJECT (window->priv->list_view),
5659 			  "row_activated",
5660 			  G_CALLBACK (row_activated_cb),
5661 			  window);
5662 	g_signal_connect (G_OBJECT (window->priv->list_view),
5663 			  "button_press_event",
5664 			  G_CALLBACK (file_button_press_cb),
5665 			  window);
5666 	g_signal_connect (G_OBJECT (window->priv->list_view),
5667 			  "button_release_event",
5668 			  G_CALLBACK (file_button_release_cb),
5669 			  window);
5670 	g_signal_connect (G_OBJECT (window->priv->list_view),
5671 			  "motion_notify_event",
5672 			  G_CALLBACK (file_motion_notify_callback),
5673 			  window);
5674 	g_signal_connect (G_OBJECT (window->priv->list_view),
5675 			  "leave_notify_event",
5676 			  G_CALLBACK (file_leave_notify_callback),
5677 			  window);
5678 	g_signal_connect (G_OBJECT (window->priv->list_view),
5679 			  "drag_begin",
5680 			  G_CALLBACK (file_list_drag_begin),
5681 			  window);
5682 	g_signal_connect (G_OBJECT (window->priv->list_view),
5683 			  "drag_end",
5684 			  G_CALLBACK (file_list_drag_end),
5685 			  window);
5686 	egg_tree_multi_drag_add_drag_support (GTK_TREE_VIEW (window->priv->list_view));
5687 
5688 	list_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5689 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_scrolled_window),
5690 					GTK_POLICY_AUTOMATIC,
5691 					GTK_POLICY_AUTOMATIC);
5692 	gtk_container_add (GTK_CONTAINER (list_scrolled_window), window->priv->list_view);
5693 
5694 	/* filter bar */
5695 
5696 	window->priv->filter_bar = gtk_search_bar_new ();
5697 	filter_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
5698 	window->priv->filter_entry = gtk_search_entry_new ();
5699 	gtk_entry_set_width_chars (GTK_ENTRY (window->priv->filter_entry), 40);
5700 	g_signal_connect (G_OBJECT (window->priv->filter_entry),
5701 			  "search-changed",
5702 			  G_CALLBACK (filter_entry_search_changed_cb),
5703 			  window);
5704 	gtk_search_bar_connect_entry (GTK_SEARCH_BAR (window->priv->filter_bar), GTK_ENTRY (window->priv->filter_entry));
5705 	gtk_container_add (GTK_CONTAINER (window->priv->filter_bar), filter_box);
5706 	gtk_box_pack_start (GTK_BOX (filter_box), window->priv->filter_entry, TRUE, TRUE, 0);
5707 	gtk_widget_show_all (window->priv->filter_bar);
5708 	fr_window_attach (FR_WINDOW (window), window->priv->filter_bar, FR_WINDOW_AREA_FILTERBAR);
5709 
5710 	/* tree view */
5711 
5712 	window->priv->tree_store = gtk_tree_store_new (TREE_NUMBER_OF_COLUMNS,
5713 						       G_TYPE_STRING,
5714 						       GDK_TYPE_PIXBUF,
5715 						       G_TYPE_STRING,
5716 						       PANGO_TYPE_WEIGHT);
5717 	window->priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->priv->tree_store));
5718 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (window->priv->tree_view), FALSE);
5719 	add_dir_tree_columns (window, GTK_TREE_VIEW (window->priv->tree_view));
5720 
5721 	g_signal_connect (G_OBJECT (window->priv->tree_view),
5722 			  "button_press_event",
5723 			  G_CALLBACK (dir_tree_button_press_cb),
5724 			  window);
5725 
5726 	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->tree_view));
5727 	g_signal_connect (selection,
5728 			  "changed",
5729 			  G_CALLBACK (dir_tree_selection_changed_cb),
5730 			  window);
5731 
5732 	g_signal_connect (G_OBJECT (window->priv->tree_view),
5733 			  "drag_begin",
5734 			  G_CALLBACK (folde_tree_drag_begin),
5735 			  window);
5736 	g_signal_connect (G_OBJECT (window->priv->tree_view),
5737 			  "drag_end",
5738 			  G_CALLBACK (file_list_drag_end),
5739 			  window);
5740 	g_signal_connect (G_OBJECT (window->priv->tree_view),
5741 			  "drag_data_get",
5742 			  G_CALLBACK (fr_window_folder_tree_drag_data_get),
5743 			  window);
5744 	gtk_drag_source_set (window->priv->tree_view,
5745 			     GDK_BUTTON1_MASK,
5746 			     folder_tree_targets, G_N_ELEMENTS (folder_tree_targets),
5747 			     GDK_ACTION_COPY);
5748 
5749 	tree_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
5750 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (tree_scrolled_window),
5751 					GTK_POLICY_AUTOMATIC,
5752 					GTK_POLICY_AUTOMATIC);
5753 	gtk_container_add (GTK_CONTAINER (tree_scrolled_window), window->priv->tree_view);
5754 
5755 	/* side pane */
5756 
5757 	window->priv->sidepane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
5758 	gtk_box_pack_start (GTK_BOX (window->priv->sidepane), tree_scrolled_window, TRUE, TRUE, 0);
5759 
5760 	/* main content */
5761 
5762 	window->priv->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
5763 	gtk_paned_pack1 (GTK_PANED (window->priv->paned), window->priv->sidepane, FALSE, TRUE);
5764 	gtk_paned_pack2 (GTK_PANED (window->priv->paned), list_scrolled_window, TRUE, TRUE);
5765 	gtk_paned_set_position (GTK_PANED (window->priv->paned), g_settings_get_int (window->priv->settings_ui, PREF_UI_SIDEBAR_WIDTH));
5766 	gtk_drag_dest_set (GTK_WIDGET (window->priv->paned),
5767 			   GTK_DEST_DEFAULT_ALL,
5768 			   target_table, G_N_ELEMENTS (target_table),
5769 			   GDK_ACTION_COPY);
5770 
5771 	g_signal_connect (G_OBJECT (window->priv->paned),
5772 			  "drag_data_received",
5773 			  G_CALLBACK (fr_window_drag_data_received),
5774 			  window);
5775 	g_signal_connect (G_OBJECT (window->priv->paned),
5776 			  "drag_motion",
5777 			  G_CALLBACK (fr_window_drag_motion),
5778 			  window);
5779 
5780 	fr_window_attach (FR_WINDOW (window), window->priv->paned, FR_WINDOW_AREA_CONTENTS);
5781 	gtk_widget_show_all (window->priv->paned);
5782 
5783         /* ui actions */
5784 
5785         g_action_map_add_action_entries (G_ACTION_MAP (window),
5786                                          fr_window_actions,
5787                                          G_N_ELEMENTS (fr_window_actions),
5788                                          window);
5789         fr_window_add_accelerators (window,
5790                                     fr_window_accelerators,
5791                                     G_N_ELEMENTS (fr_window_accelerators));
5792 
5793 	/* header bar */
5794 
5795 	window->priv->headerbar = gtk_header_bar_new ();
5796 	gtk_widget_show (window->priv->headerbar);
5797 	gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (window->priv->headerbar), TRUE);
5798 	gtk_window_set_titlebar (GTK_WINDOW (window), window->priv->headerbar);
5799 
5800 	/* header bar buttons */
5801 
5802 	header_bar_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
5803 
5804 	button = _gtk_header_bar_create_text_button (C_("Action", "Extract"), NULL, "win.extract-files");
5805 	gtk_size_group_add_widget (header_bar_size_group, button);
5806 	gtk_header_bar_pack_start (GTK_HEADER_BAR (window->priv->headerbar), button);
5807 
5808 	button = _gtk_header_bar_create_image_button ("list-add-symbolic", C_("Action", "Add Files"), "win.add-files");
5809 	gtk_size_group_add_widget (header_bar_size_group, button);
5810 	gtk_header_bar_pack_start (GTK_HEADER_BAR (window->priv->headerbar), button);
5811 
5812 #if ! GTK_CHECK_VERSION(3,11,4)
5813 	button = _gtk_header_bar_create_image_toggle_button ("edit-find-symbolic", _("Find files by name"), "win.find");
5814 	gtk_size_group_add_widget (header_bar_size_group, button);
5815 	gtk_header_bar_pack_end (GTK_HEADER_BAR (window->priv->headerbar), button);
5816 #endif
5817 
5818         /* gears menu button */
5819 
5820         {
5821                 GtkBuilder *builder;
5822                 GMenuModel *menu;
5823 
5824                 builder = _gtk_builder_new_from_resource ("gears-menu.ui");
5825                 menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
5826                 button = _gtk_menu_button_new_for_header_bar ();
5827                 gtk_size_group_add_widget (header_bar_size_group, button);
5828 #if ! GTK_CHECK_VERSION(3,13,0)
5829 		gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name ("emblem-system-symbolic", GTK_ICON_SIZE_MENU));
5830 #else
5831                 gtk_menu_button_set_direction (GTK_MENU_BUTTON (button), GTK_ARROW_NONE);
5832 #endif
5833                 gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), menu);
5834                 gtk_widget_show_all (button);
5835                 gtk_header_bar_pack_end (GTK_HEADER_BAR (window->priv->headerbar), button);
5836 
5837                 _gtk_window_add_accelerators_from_menu ((GTK_WINDOW (window)), menu);
5838 
5839                 g_object_unref (builder);
5840         }
5841 
5842 #if GTK_CHECK_VERSION(3,11,4)
5843 	button = _gtk_header_bar_create_image_toggle_button ("edit-find-symbolic", _("Find files by name"), "win.find");
5844 	gtk_size_group_add_widget (header_bar_size_group, button);
5845 	gtk_header_bar_pack_end (GTK_HEADER_BAR (window->priv->headerbar), button);
5846 #endif
5847 
5848         g_object_unref (header_bar_size_group);
5849 
5850 	/* location bar */
5851 
5852 	window->priv->location_bar = fr_location_bar_new ();
5853 
5854 	location_bar_content = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
5855 	gtk_container_set_border_width (GTK_CONTAINER (location_bar_content), 4);
5856 	gtk_box_pack_start (GTK_BOX (window->priv->location_bar), location_bar_content, TRUE, TRUE, 0);
5857 
5858 	navigation_commands = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
5859 	gtk_box_pack_start (GTK_BOX (navigation_commands),
5860 			    _gtk_header_bar_create_image_button ("go-previous-symbolic", _("Go to the previous visited location"), "win.go-back"),
5861 			    FALSE,
5862 			    FALSE,
5863 			    0);
5864 	gtk_box_pack_start (GTK_BOX (navigation_commands),
5865 			    _gtk_header_bar_create_image_button ("go-next-symbolic", _("Go to the next visited location"), "win.go-forward"),
5866 			    FALSE,
5867 			    FALSE,
5868 			    0);
5869 	gtk_widget_show_all (navigation_commands);
5870 	gtk_style_context_add_class (gtk_widget_get_style_context (navigation_commands), GTK_STYLE_CLASS_RAISED);
5871 	gtk_style_context_add_class (gtk_widget_get_style_context (navigation_commands), GTK_STYLE_CLASS_LINKED);
5872 	gtk_box_pack_start (GTK_BOX (location_bar_content), navigation_commands, FALSE, FALSE, 0);
5873 
5874 	gtk_box_pack_start (GTK_BOX (location_bar_content),
5875 			    _gtk_header_bar_create_image_button ("user-home-symbolic", _("Go to the home location"), "win.go-home"),
5876 			    FALSE,
5877 			    FALSE,
5878 			    0);
5879 
5880 	/* current location */
5881 
5882 	location_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
5883 	/* Translators: after the colon there is a folder name. */
5884 	window->priv->location_label = gtk_label_new_with_mnemonic (_("_Location:"));
5885 	gtk_box_pack_start (GTK_BOX (location_box), window->priv->location_label, FALSE, FALSE, 5);
5886 
5887 	window->priv->location_entry = gtk_entry_new ();
5888 	gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->priv->location_entry),
5889 					   GTK_ENTRY_ICON_PRIMARY,
5890 					   "folder-symbolic");
5891 	g_signal_connect (G_OBJECT (window->priv->location_entry),
5892 			  "key_press_event",
5893 			  G_CALLBACK (location_entry_key_press_event_cb),
5894 			  window);
5895 	gtk_box_pack_start (GTK_BOX (location_box), window->priv->location_entry, TRUE, TRUE, 5);
5896 	gtk_box_pack_start (GTK_BOX (location_bar_content), location_box, TRUE, TRUE, 0);
5897 
5898 	gtk_widget_show_all (window->priv->location_bar);
5899 	fr_window_attach (FR_WINDOW (window), window->priv->location_bar, FR_WINDOW_AREA_LOCATIONBAR);
5900 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)
5901 		gtk_widget_hide (window->priv->location_bar);
5902 	else
5903 		gtk_widget_show (window->priv->location_bar);
5904 
5905 	/* popup menus */
5906 	{
5907 		GtkBuilder *builder;
5908 
5909 		builder = _gtk_builder_new_from_resource ("menus.ui");
5910 
5911 		window->priv->file_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "file-popup")));
5912 		gtk_menu_attach_to_widget (GTK_MENU (window->priv->file_popup_menu), GTK_WIDGET (window), NULL);
5913 
5914 		window->priv->folder_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "folder-popup")));
5915 		gtk_menu_attach_to_widget (GTK_MENU (window->priv->folder_popup_menu), GTK_WIDGET (window), NULL);
5916 
5917 		window->priv->sidebar_folder_popup_menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder, "sidebar-popup")));
5918 		gtk_menu_attach_to_widget (GTK_MENU (window->priv->sidebar_folder_popup_menu), GTK_WIDGET (window), NULL);
5919 
5920 		g_object_unref (builder);
5921 	}
5922 
5923 	/**/
5924 
5925 	fr_window_update_title (window);
5926 	fr_window_update_sensitivity (window);
5927 	fr_window_update_current_location (window);
5928 	fr_window_update_columns_visibility (window);
5929 
5930 	/* Add notification callbacks. */
5931 
5932 	g_signal_connect (window->priv->settings_ui,
5933 			  "changed::" PREF_UI_VIEW_SIDEBAR,
5934 			  G_CALLBACK (pref_view_folders_changed),
5935 			  window);
5936 	g_signal_connect (window->priv->settings_listing,
5937 			  "changed::" PREF_LISTING_SHOW_TYPE,
5938 			  G_CALLBACK (pref_show_field_changed),
5939 			  window);
5940 	g_signal_connect (window->priv->settings_listing,
5941 			  "changed::" PREF_LISTING_SHOW_SIZE,
5942 			  G_CALLBACK (pref_show_field_changed),
5943 			  window);
5944 	g_signal_connect (window->priv->settings_listing,
5945 			  "changed::" PREF_LISTING_SHOW_TIME,
5946 			  G_CALLBACK (pref_show_field_changed),
5947 			  window);
5948 	g_signal_connect (window->priv->settings_listing,
5949 			  "changed::" PREF_LISTING_SHOW_PATH,
5950 			  G_CALLBACK (pref_show_field_changed),
5951 			  window);
5952 	g_signal_connect (window->priv->settings_listing,
5953 			  "changed::" PREF_LISTING_LIST_MODE,
5954 			  G_CALLBACK (pref_list_mode_changed),
5955 			  window);
5956 
5957 	if (window->priv->settings_nautilus)
5958 		g_signal_connect (window->priv->settings_nautilus,
5959 				  "changed::" NAUTILUS_CLICK_POLICY,
5960 				  G_CALLBACK (pref_click_policy_changed),
5961 				  window);
5962 
5963 	/* Give focus to the list. */
5964 
5965 	gtk_widget_grab_focus (window->priv->list_view);
5966 }
5967 
5968 
5969 GtkWidget *
fr_window_new(void)5970 fr_window_new (void)
5971 {
5972 	GtkWidget *window;
5973 
5974 	window = g_object_new (FR_TYPE_WINDOW, "application", g_application_get_default (), NULL);
5975 	fr_window_construct ((FrWindow*) window);
5976 
5977 	return window;
5978 }
5979 
5980 
5981 static void
_fr_window_set_archive(FrWindow * window,FrArchive * archive)5982 _fr_window_set_archive (FrWindow  *window,
5983 			FrArchive *archive)
5984 {
5985 	if (window->archive != NULL) {
5986 		g_signal_handlers_disconnect_by_data (window->archive, window);
5987 		g_object_unref (window->archive);
5988 	}
5989 
5990 	window->archive = _g_object_ref (archive);
5991 
5992 	if (window->archive == NULL)
5993 		return;
5994 
5995 	g_signal_connect (G_OBJECT (window->archive),
5996 			  "progress",
5997 			  G_CALLBACK (fr_archive_progress_cb),
5998 			  window);
5999 	g_signal_connect (G_OBJECT (window->archive),
6000 			  "message",
6001 			  G_CALLBACK (fr_archive_message_cb),
6002 			  window);
6003 	g_signal_connect (G_OBJECT (window->archive),
6004 			  "start",
6005 			  G_CALLBACK (fr_archive_start_cb),
6006 			  window);
6007 	g_signal_connect (G_OBJECT (window->archive),
6008 			  "stoppable",
6009 			  G_CALLBACK (fr_archive_stoppable_cb),
6010 			  window);
6011 	g_signal_connect (G_OBJECT (window->archive),
6012 			  "working-archive",
6013 			  G_CALLBACK (fr_window_working_archive_cb),
6014 			  window);
6015 }
6016 
6017 
6018 static void
_fr_window_set_archive_file(FrWindow * window,GFile * file)6019 _fr_window_set_archive_file (FrWindow *window,
6020 			     GFile    *file)
6021 {
6022 	_g_object_unref (window->priv->archive_file);
6023 	window->priv->archive_file = _g_object_ref (file);
6024 }
6025 
6026 
6027 gboolean
fr_window_archive_new(FrWindow * window,GFile * file,const char * mime_type)6028 fr_window_archive_new (FrWindow   *window,
6029 		       GFile      *file,
6030 		       const char *mime_type)
6031 {
6032 	FrArchive *archive;
6033 
6034 	g_return_val_if_fail (window != NULL, FALSE);
6035 
6036 	archive = fr_archive_create (file, mime_type);
6037 	if (archive != NULL) {
6038 		fr_window_archive_close (window);
6039 		_fr_window_set_archive (window, archive);
6040 		_fr_window_set_archive_file (window, file);
6041 		window->priv->archive_present = TRUE;
6042 		window->priv->archive_new = TRUE;
6043 
6044 		g_object_unref (archive);
6045 	}
6046 
6047 	return archive != NULL;
6048 }
6049 
6050 
6051 static void
archive_list_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6052 archive_list_ready_cb (GObject      *source_object,
6053 		       GAsyncResult *result,
6054 		       gpointer      user_data)
6055 {
6056 	FrWindow *window = user_data;
6057 	GError   *error = NULL;
6058 
6059 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6060 	_archive_operation_completed (window, FR_ACTION_LISTING_CONTENT, error);
6061 
6062 	_g_error_free (error);
6063 }
6064 
6065 
6066 static void
fr_window_archive_list(FrWindow * window)6067 fr_window_archive_list (FrWindow *window)
6068 {
6069 	if (! fr_archive_is_capable_of (window->archive, FR_ARCHIVE_CAN_READ)) {
6070 		fr_window_archive_close (window);
6071 		fr_window_archive_open (window, window->priv->archive_file, NULL);
6072 		return;
6073 	}
6074 
6075 	_archive_operation_started (window, FR_ACTION_LISTING_CONTENT);
6076 	fr_archive_list (window->archive,
6077 			 window->priv->password,
6078 			 window->priv->cancellable,
6079 			 archive_list_ready_cb,
6080 			 window);
6081 }
6082 
6083 
6084 static void
archive_open_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6085 archive_open_ready_cb (GObject      *source_object,
6086 		       GAsyncResult *result,
6087 		       gpointer      user_data)
6088 {
6089 	FrWindow  *window = user_data;
6090 	FrArchive *archive;
6091 	GError    *error = NULL;
6092 
6093 	archive = fr_archive_open_finish (G_FILE (source_object), result, &error);
6094 	_fr_window_set_archive (window, archive);
6095 
6096 	g_signal_emit (window,
6097 		       fr_window_signals[ARCHIVE_LOADED],
6098 		       0,
6099 		       error == NULL);
6100 
6101 	_archive_operation_completed (window, FR_ACTION_LOADING_ARCHIVE, error);
6102 	_g_error_free (error);
6103 	_g_object_unref (archive);
6104 }
6105 
6106 
6107 FrWindow *
fr_window_archive_open(FrWindow * current_window,GFile * file,GtkWindow * parent)6108 fr_window_archive_open (FrWindow   *current_window,
6109 			GFile      *file,
6110 			GtkWindow  *parent)
6111 {
6112 	FrWindow *window = current_window;
6113 
6114 	g_return_val_if_fail (file != NULL, FALSE);
6115 
6116 	if (current_window->priv->archive_present)
6117 		window = (FrWindow *) fr_window_new ();
6118 
6119 	g_return_val_if_fail (window != NULL, FALSE);
6120 
6121 	fr_window_archive_close (window);
6122 	_fr_window_set_archive_file (window, file);
6123 	window->priv->give_focus_to_the_list = TRUE;
6124 	window->priv->load_error_parent_window = parent;
6125 
6126 	_archive_operation_started (window, FR_ACTION_LOADING_ARCHIVE);
6127 
6128 	/* this is used to reload the archive after asking a password */
6129 	fr_window_set_current_action (window,
6130 					    FR_BATCH_ACTION_LOAD,
6131 					    g_object_ref (file),
6132 					    (GFreeFunc) g_object_unref);
6133 
6134 	fr_archive_open (file,
6135 			 window->priv->cancellable,
6136 			 archive_open_ready_cb,
6137 			 window);
6138 
6139 	return window;
6140 }
6141 
6142 
6143 void
fr_window_archive_close(FrWindow * window)6144 fr_window_archive_close (FrWindow *window)
6145 {
6146 	g_return_if_fail (window != NULL);
6147 
6148 	if (! window->priv->archive_new && ! window->priv->archive_present)
6149 		return;
6150 
6151 	fr_window_free_open_files (window);
6152 	fr_clipboard_data_unref (window->priv->copy_data);
6153 	window->priv->copy_data = NULL;
6154 
6155 	fr_window_set_password (window, NULL);
6156 	fr_window_set_volume_size (window, 0);
6157 	fr_window_history_clear (window);
6158 
6159 	_fr_window_set_archive (window, NULL);
6160 	window->priv->archive_new = FALSE;
6161 	window->priv->archive_present = FALSE;
6162 
6163 	fr_window_update_title (window);
6164 	fr_window_update_sensitivity (window);
6165 	fr_window_update_file_list (window, FALSE);
6166 	fr_window_update_dir_tree (window);
6167 	fr_window_update_current_location (window);
6168 }
6169 
6170 
6171 GFile *
fr_window_get_archive_file(FrWindow * window)6172 fr_window_get_archive_file (FrWindow *window)
6173 {
6174 	g_return_val_if_fail (window != NULL, NULL);
6175 
6176 	return window->priv->archive_file;
6177 }
6178 
6179 
6180 GFile *
fr_window_get_archive_file_for_paste(FrWindow * window)6181 fr_window_get_archive_file_for_paste (FrWindow *window)
6182 {
6183 	g_return_val_if_fail (window != NULL, NULL);
6184 
6185 	if (window->priv->clipboard_data != NULL)
6186 		return window->priv->clipboard_data->file;
6187 	else
6188 		return NULL;
6189 }
6190 
6191 
6192 gboolean
fr_window_archive_is_present(FrWindow * window)6193 fr_window_archive_is_present (FrWindow *window)
6194 {
6195 	g_return_val_if_fail (window != NULL, FALSE);
6196 
6197 	return window->priv->archive_present;
6198 }
6199 
6200 
6201 void
fr_window_archive_reload(FrWindow * window)6202 fr_window_archive_reload (FrWindow *window)
6203 {
6204 	g_return_if_fail (window != NULL);
6205 
6206 	if (window->priv->activity_ref > 0)
6207 		return;
6208 	if (window->priv->archive_new)
6209 		return;
6210 	if (window->archive == NULL)
6211 		return;
6212 
6213 	fr_window_archive_list (window);
6214 }
6215 
6216 
6217 /**/
6218 
6219 
6220 #ifdef ENABLE_NOTIFICATION
6221 
6222 
6223 static void
notify_action_open_archive_cb(NotifyNotification * notification,char * action,gpointer user_data)6224 notify_action_open_archive_cb (NotifyNotification *notification,
6225 			       char               *action,
6226 			       gpointer            user_data)
6227 {
6228 	GFile     *saved_file = user_data;
6229 	GtkWidget *new_window;
6230 
6231 	new_window = fr_window_new ();
6232 	gtk_widget_show (new_window);
6233 	fr_window_archive_open (FR_WINDOW (new_window),
6234 				saved_file,
6235 				GTK_WINDOW (new_window));
6236 }
6237 
6238 
6239 static void
_fr_window_notify_creation_complete(FrWindow * window)6240 _fr_window_notify_creation_complete (FrWindow *window)
6241 {
6242 	char               *basename;
6243 	char               *message;
6244 	NotifyNotification *notification;
6245 	gboolean            notification_supports_actions;
6246 	GList              *caps;
6247 
6248 	basename = _g_file_get_display_basename (window->priv->saving_file);
6249 	/* Translators: %s is a filename */
6250 	message = g_strdup_printf (_("“%s” created successfully"), basename);
6251 	notification = notify_notification_new (window->priv->batch_title, message, "file-roller");
6252 	notify_notification_set_hint_string (notification, "desktop-entry", "file-roller");
6253 
6254 	notification_supports_actions = FALSE;
6255 	caps = notify_get_server_caps ();
6256 	if (caps != NULL) {
6257 		notification_supports_actions = g_list_find_custom (caps, "actions", (GCompareFunc) strcmp) != NULL;
6258 		_g_string_list_free (caps);
6259 	}
6260 
6261 	if (notification_supports_actions) {
6262 		notify_notification_add_action (notification,
6263 						"document-open-symbolic",
6264 						C_("Action", "Open"),
6265 						notify_action_open_archive_cb,
6266 						g_object_ref (window->priv->saving_file),
6267 						g_object_unref);
6268 		/*notify_notification_set_hint (notification,
6269 					      "action-icons",
6270 					      g_variant_new_boolean (TRUE));*/
6271 	}
6272 
6273 	notify_notification_show (notification, NULL);
6274 	g_free (message);
6275 	g_free (basename);
6276 }
6277 
6278 
6279 #else
6280 
6281 
6282 static void
_fr_window_notify_creation_complete(FrWindow * window)6283 _fr_window_notify_creation_complete (FrWindow *window)
6284 {
6285 	gtk_window_present (GTK_WINDOW (window->priv->progress_dialog));
6286 }
6287 
6288 
6289 #endif
6290 
6291 
6292 static void
archive_add_files_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6293 archive_add_files_ready_cb (GObject      *source_object,
6294 			    GAsyncResult *result,
6295 			    gpointer      user_data)
6296 {
6297 	FrWindow *window = user_data;
6298 	gboolean  notify;
6299 	GError   *error = NULL;
6300 
6301 	notify = window->priv->notify;
6302 
6303 	g_object_ref (window);
6304 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6305 	_archive_operation_completed (window, FR_ACTION_ADDING_FILES, error);
6306 
6307 	if ((error == NULL) && notify) {
6308 		window->priv->destroy_with_confirmation_dialog = TRUE;
6309 		fr_window_show_confirmation_dialog_with_open_archive (window);
6310 
6311 		if (! gtk_window_has_toplevel_focus (GTK_WINDOW (window->priv->progress_dialog)))
6312 			_fr_window_notify_creation_complete (window);
6313 	}
6314 
6315 	_g_error_free (error);
6316 	g_object_unref (window);
6317 }
6318 
6319 
6320 void
fr_window_archive_add_files(FrWindow * window,GList * file_list,GFile * base_dir,gboolean update)6321 fr_window_archive_add_files (FrWindow   *window,
6322 			     GList      *file_list, /* GFile list */
6323 			     GFile      *base_dir,
6324 			     gboolean    update)
6325 {
6326 	_archive_operation_started (window, FR_ACTION_ADDING_FILES);
6327 
6328 	fr_archive_add_files (window->archive,
6329 			      file_list,
6330 			      base_dir,
6331 			      fr_window_get_current_location (window),
6332 			      update,
6333 			      FALSE,
6334 			      window->priv->password,
6335 			      window->priv->encrypt_header,
6336 			      window->priv->compression,
6337 			      window->priv->volume_size,
6338 			      window->priv->cancellable,
6339 			      archive_add_files_ready_cb,
6340 			      window);
6341 }
6342 
6343 
6344 void
fr_window_archive_add_with_filter(FrWindow * window,GList * file_list,GFile * base_dir,const char * include_files,const char * exclude_files,const char * exclude_folders,const char * dest_dir,gboolean update,gboolean follow_links)6345 fr_window_archive_add_with_filter (FrWindow      *window,
6346 				   GList         *file_list, /* GFile list */
6347 				   GFile         *base_dir,
6348 				   const char    *include_files,
6349 				   const char    *exclude_files,
6350 				   const char    *exclude_folders,
6351 				   const char    *dest_dir,
6352 				   gboolean       update,
6353 				   gboolean       follow_links)
6354 {
6355 	_archive_operation_started (window, FR_ACTION_ADDING_FILES);
6356 
6357 	fr_archive_add_files_with_filter (window->archive,
6358 					  file_list,
6359 					  base_dir,
6360 					  include_files,
6361 					  exclude_files,
6362 					  exclude_folders,
6363 					  (dest_dir == NULL)? fr_window_get_current_location (window): dest_dir,
6364 					  update,
6365 					  follow_links,
6366 					  window->priv->password,
6367 					  window->priv->encrypt_header,
6368 					  window->priv->compression,
6369 					  window->priv->volume_size,
6370 					  window->priv->cancellable,
6371 					  archive_add_files_ready_cb,
6372 					  window);
6373 }
6374 
6375 
6376 void
fr_window_archive_add_dropped_items(FrWindow * window,GList * file_list)6377 fr_window_archive_add_dropped_items (FrWindow *window,
6378 				     GList    *file_list)
6379 {
6380 	_archive_operation_started (window, FR_ACTION_ADDING_FILES);
6381 
6382 	fr_archive_add_dropped_items (window->archive,
6383 				      file_list,
6384 				      fr_window_get_current_location (window),
6385 				      window->priv->password,
6386 				      window->priv->encrypt_header,
6387 				      window->priv->compression,
6388 				      window->priv->volume_size,
6389 				      window->priv->cancellable,
6390 				      archive_add_files_ready_cb,
6391 				      window);
6392 }
6393 
6394 
6395 /* -- fr_window_archive_remove -- */
6396 
6397 
6398 static void
archive_remove_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6399 archive_remove_ready_cb (GObject      *source_object,
6400 			 GAsyncResult *result,
6401 			 gpointer      user_data)
6402 {
6403 	FrWindow *window = user_data;
6404 	GError   *error = NULL;
6405 
6406 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6407 	_archive_operation_completed (window, FR_ACTION_DELETING_FILES, error);
6408 
6409 	_g_error_free (error);
6410 }
6411 
6412 
6413 void
fr_window_archive_remove(FrWindow * window,GList * file_list)6414 fr_window_archive_remove (FrWindow *window,
6415 			  GList    *file_list)
6416 {
6417 	GList *new_file_list;
6418 
6419 	new_file_list = _g_string_list_dup (file_list);
6420 	fr_window_set_current_action (window,
6421 					    FR_BATCH_ACTION_REMOVE,
6422 					    new_file_list,
6423 					    (GFreeFunc) _g_string_list_free);
6424 
6425 	_archive_operation_started (window, FR_ACTION_DELETING_FILES);
6426 
6427 	g_object_set (window->archive,
6428 		      "compression", window->priv->compression,
6429 		      "encrypt-header", window->priv->encrypt_header,
6430 		      "password", window->priv->password,
6431 		      "volume-size", window->priv->volume_size,
6432 		      NULL);
6433 
6434 	fr_window_clipboard_remove_file_list (window, file_list);
6435 	fr_archive_remove (window->archive,
6436 			   new_file_list,
6437 			   window->priv->compression,
6438 			   window->priv->cancellable,
6439 			   archive_remove_ready_cb,
6440 			   window);
6441 }
6442 
6443 
6444 /* -- fr_window_archive_extract -- */
6445 
6446 
6447 static ExtractData *
extract_data_new(FrWindow * window,GList * file_list,GFile * destination,const char * base_dir,gboolean skip_older,FrOverwrite overwrite,gboolean junk_paths,gboolean ask_to_open_destination,gboolean avoid_tarbombs)6448 extract_data_new (FrWindow    *window,
6449 		  GList       *file_list,
6450 		  GFile       *destination,
6451 		  const char  *base_dir,
6452 		  gboolean     skip_older,
6453 		  FrOverwrite  overwrite,
6454 		  gboolean     junk_paths,
6455 		  gboolean     ask_to_open_destination,
6456 		  gboolean     avoid_tarbombs)
6457 {
6458 	ExtractData *edata;
6459 
6460 	edata = g_new0 (ExtractData, 1);
6461 	edata->window = _g_object_ref (window);
6462 	edata->file_list = _g_string_list_dup (file_list);
6463 	edata->destination = _g_object_ref (destination);
6464 	edata->skip_older = skip_older;
6465 	edata->overwrite = overwrite;
6466 	edata->junk_paths = junk_paths;
6467 	if (base_dir != NULL)
6468 		edata->base_dir = g_strdup (base_dir);
6469 	edata->ask_to_open_destination = ask_to_open_destination;
6470 	edata->avoid_tarbombs = avoid_tarbombs;
6471 
6472 	return edata;
6473 }
6474 
6475 
6476 static void
extract_data_free(ExtractData * edata)6477 extract_data_free (ExtractData *edata)
6478 {
6479 	g_return_if_fail (edata != NULL);
6480 
6481 	_g_string_list_free (edata->file_list);
6482 	_g_object_unref (edata->destination);
6483 	_g_object_unref (edata->window);
6484 	g_free (edata->base_dir);
6485 
6486 	g_free (edata);
6487 }
6488 
6489 
6490 typedef struct {
6491 	FrWindow    *window;
6492 	ExtractData *edata;
6493 	GList       *current_file;
6494 	gboolean     extract_all;
6495 } OverwriteData;
6496 
6497 
6498 #define _FR_RESPONSE_OVERWRITE_YES_ALL 100
6499 #define _FR_RESPONSE_OVERWRITE_YES     101
6500 #define _FR_RESPONSE_OVERWRITE_NO      102
6501 #define _FR_RESPONSE_OVERWRITE_NO_ALL  103
6502 
6503 
6504 static void
archive_extraction_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6505 archive_extraction_ready_cb (GObject      *source_object,
6506 			     GAsyncResult *result,
6507 			     gpointer      user_data)
6508 {
6509 	ExtractData *edata = user_data;
6510 	FrWindow    *window = edata->window;
6511 	gboolean     ask_to_open_destination;
6512 	gboolean     batch_mode;
6513 	GError      *error = NULL;
6514 
6515 	batch_mode = window->priv->batch_mode;
6516 	ask_to_open_destination = edata->ask_to_open_destination;
6517 	g_object_ref (window);
6518 
6519 	_g_clear_object (&window->priv->last_extraction_destination);
6520 	window->priv->last_extraction_destination = _g_object_ref (fr_archive_get_last_extraction_destination (window->archive));
6521 
6522 	_g_object_list_unref (window->priv->last_extraction_files_first_level);
6523 	window->priv->last_extraction_files_first_level = NULL;
6524 
6525 	if (ask_to_open_destination && ! edata->junk_paths) {
6526 		/* collect the files to show in the file manager */
6527 
6528 		GHashTable *names_hash;
6529 		gboolean    stop = FALSE;
6530 		int         i;
6531 
6532 		names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
6533 		for (i = 0; ! stop && (i < window->archive->files->len); i++) {
6534 			FileData *fdata = g_ptr_array_index (window->archive->files, i);
6535 			char     *first_level;
6536 			char     *second_slash;
6537 
6538 			if ((fdata->full_path == NULL) || (fdata->full_path[0] == 0))
6539 				continue;
6540 
6541 			second_slash = strchr (fdata->full_path + 1, '/');
6542 			if (second_slash != NULL)
6543 				first_level = g_strndup (fdata->full_path, second_slash - fdata->full_path);
6544 			else
6545 				first_level = g_strdup (fdata->full_path);
6546 
6547 			/* avoid to insert duplicated entries */
6548 
6549 			if (g_hash_table_lookup (names_hash, first_level) == NULL) {
6550 
6551 				/* only use this list if there is a single entry,
6552 				 * because Nautilus opens a window for each file
6553 				 * even when the files are all in the same folder.  */
6554 
6555 				if (window->priv->last_extraction_files_first_level != NULL) {
6556 					_g_object_list_unref (window->priv->last_extraction_files_first_level);
6557 					window->priv->last_extraction_files_first_level = NULL;
6558 					stop = TRUE;
6559 				}
6560 				else {
6561 					g_hash_table_insert (names_hash, g_strdup (first_level), GINT_TO_POINTER (1));
6562 					window->priv->last_extraction_files_first_level = g_list_prepend (window->priv->last_extraction_files_first_level, _g_file_append_path (window->priv->last_extraction_destination, first_level, NULL));
6563 				}
6564 			}
6565 
6566 			g_free (first_level);
6567 		}
6568 
6569 		g_hash_table_destroy (names_hash);
6570 	}
6571 
6572 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
6573 	_archive_operation_completed (window, FR_ACTION_EXTRACTING_FILES, error);
6574 	if ((error == NULL) || (error->code != FR_ERROR_ASK_PASSWORD))
6575 		fr_window_dnd_extraction_finished (window, error != NULL);
6576 
6577 	if ((error == NULL) && ask_to_open_destination) {
6578 		window->priv->destroy_with_confirmation_dialog = window->priv->batch_mode;
6579 		fr_window_show_confirmation_dialog_with_open_destination (window);
6580 	}
6581 	else if ((error == NULL) && ! batch_mode && ! gtk_window_has_toplevel_focus (GTK_WINDOW (window->priv->progress_dialog)))
6582 		gtk_window_present (GTK_WINDOW (window));
6583 
6584 	_g_error_free (error);
6585 	g_object_unref (window);
6586 }
6587 
6588 
6589 static void
_fr_window_archive_extract_from_edata(FrWindow * window,ExtractData * edata)6590 _fr_window_archive_extract_from_edata (FrWindow    *window,
6591 				       ExtractData *edata)
6592 {
6593 	GList *scan;
6594 	gsize  total_size;
6595 
6596 	total_size = 0;
6597 	for (scan = edata->file_list; scan; scan = scan->next) {
6598 		char     *filename = scan->data;
6599 		FileData *file_data;
6600 
6601 		file_data = g_hash_table_lookup (window->archive->files_hash, filename);
6602 		if (file_data == NULL)
6603 			continue;
6604 
6605 		total_size += file_data->size;
6606 	}
6607 	fr_archive_progress_set_total_bytes (window->archive, total_size);
6608 
6609 	_archive_operation_started (window, FR_ACTION_EXTRACTING_FILES);
6610 
6611 	fr_archive_extract (window->archive,
6612 			    edata->file_list,
6613 			    edata->destination,
6614 			    edata->base_dir,
6615 			    edata->skip_older,
6616 			    edata->overwrite == FR_OVERWRITE_YES,
6617 			    edata->junk_paths,
6618 			    window->priv->password,
6619 			    window->priv->cancellable,
6620 			    archive_extraction_ready_cb,
6621 			    edata);
6622 }
6623 
6624 
6625 static void _fr_window_ask_overwrite_dialog (OverwriteData *odata);
6626 
6627 
6628 static OverwriteData *
overwrite_data_new(FrWindow * window)6629 overwrite_data_new (FrWindow *window)
6630 {
6631 	OverwriteData *odata;
6632 
6633 	odata = g_new0 (OverwriteData, 1);
6634 	odata->window = _g_object_ref (window);
6635 	odata->edata = NULL;
6636 	odata->current_file = NULL;
6637 	odata->extract_all = FALSE;
6638 
6639 	return odata;
6640 }
6641 
6642 
6643 static void
overwrite_data_free(OverwriteData * odata)6644 overwrite_data_free (OverwriteData *odata)
6645 {
6646 	_g_object_unref (odata->window);
6647 	g_free (odata);
6648 }
6649 
6650 
6651 /* remove the file from the list to extract */
6652 static void
overwrite_data_skip_current(OverwriteData * odata)6653 overwrite_data_skip_current (OverwriteData *odata)
6654 {
6655 	GList *next = odata->current_file->next;
6656 
6657 	odata->edata->file_list = g_list_remove_link (odata->edata->file_list, odata->current_file);
6658 	_g_string_list_free (odata->current_file);
6659 	odata->current_file = next;
6660 	odata->extract_all = FALSE;
6661 }
6662 
6663 
6664 static void
overwrite_dialog_response_cb(GtkDialog * dialog,int response_id,gpointer user_data)6665 overwrite_dialog_response_cb (GtkDialog *dialog,
6666 			      int        response_id,
6667 			      gpointer   user_data)
6668 {
6669 	OverwriteData *odata = user_data;
6670 	gboolean       do_not_extract = FALSE;
6671 
6672 	switch (response_id) {
6673 	case _FR_RESPONSE_OVERWRITE_YES_ALL:
6674 		odata->edata->overwrite = FR_OVERWRITE_YES;
6675 		break;
6676 
6677 	case _FR_RESPONSE_OVERWRITE_YES:
6678 		odata->current_file = odata->current_file->next;
6679 		break;
6680 
6681 	case _FR_RESPONSE_OVERWRITE_NO_ALL:
6682 		overwrite_data_skip_current (odata);
6683 		odata->edata->overwrite = FR_OVERWRITE_NO;
6684 		break;
6685 
6686 	case _FR_RESPONSE_OVERWRITE_NO:
6687 		overwrite_data_skip_current (odata);
6688 		break;
6689 
6690 	case GTK_RESPONSE_DELETE_EVENT:
6691 	case GTK_RESPONSE_CANCEL:
6692 		do_not_extract = TRUE;
6693 		break;
6694 
6695 	default:
6696 		break;
6697 	}
6698 
6699 	gtk_widget_destroy (GTK_WIDGET (dialog));
6700 
6701 	if (do_not_extract) {
6702 		fr_window_batch_stop (odata->window);
6703 		fr_window_dnd_extraction_finished (odata->window, FALSE);
6704 		overwrite_data_free (odata);
6705 		return;
6706 	}
6707 
6708 	_fr_window_ask_overwrite_dialog (odata);
6709 }
6710 
6711 
6712 static void
query_info_ready_for_overwrite_dialog_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)6713 query_info_ready_for_overwrite_dialog_cb (GObject      *source_object,
6714 					  GAsyncResult *result,
6715 					  gpointer      user_data)
6716 {
6717 	OverwriteData *odata = user_data;
6718 	GFile         *destination = G_FILE (source_object);
6719 	GFileInfo     *info;
6720 	GFileType      file_type;
6721 
6722 	info = g_file_query_info_finish (destination, result, NULL);
6723 
6724 	/* file does not exist -> keep in the files to extract. */
6725 
6726 	if (info == NULL) {
6727 		odata->current_file = odata->current_file->next;
6728 		_fr_window_ask_overwrite_dialog (odata);
6729 		g_object_unref (destination);
6730 		return;
6731 	}
6732 
6733 	/* file exists and user selected "Overwrite Nothing" -> automatically
6734 	 * skip the file. */
6735 
6736 	if (odata->edata->overwrite == FR_OVERWRITE_NO) {
6737 		overwrite_data_skip_current (odata);
6738 		_fr_window_ask_overwrite_dialog (odata);
6739 		g_object_unref (destination);
6740 		return;
6741 	}
6742 
6743 	/* file exists and odata->edata->overwrite == FR_OVERWRITE_ASK */
6744 
6745 	file_type = g_file_info_get_file_type (info);
6746 	if ((file_type != G_FILE_TYPE_UNKNOWN) && (file_type != G_FILE_TYPE_DIRECTORY)) {
6747 		char      *msg;
6748 		GFile     *parent;
6749 		char      *parent_name;
6750 		char      *details;
6751 		GtkWidget *d;
6752 
6753 		msg = g_strdup_printf (_("Replace file “%s”?"), g_file_info_get_display_name (info));
6754 		parent = g_file_get_parent (destination);
6755 		parent_name = g_file_get_parse_name (parent);
6756 		details = g_strdup_printf (_("Another file with the same name already exists in “%s”."), parent_name);
6757 		d = _gtk_message_dialog_new (GTK_WINDOW (odata->window),
6758 					     GTK_DIALOG_MODAL,
6759 					     msg,
6760 					     details,
6761 					     _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
6762 					     _("Replace _All"), _FR_RESPONSE_OVERWRITE_YES_ALL,
6763 					     _("Replace _Nothing"), _FR_RESPONSE_OVERWRITE_NO_ALL,
6764 					     _("_Skip"), _FR_RESPONSE_OVERWRITE_NO,
6765 					     _("_Replace"), _FR_RESPONSE_OVERWRITE_YES,
6766 					     NULL);
6767 		gtk_dialog_set_default_response (GTK_DIALOG (d), _FR_RESPONSE_OVERWRITE_YES);
6768 		g_signal_connect (d,
6769 				  "response",
6770 				  G_CALLBACK (overwrite_dialog_response_cb),
6771 				  odata);
6772 		gtk_widget_show (d);
6773 
6774 		g_free (msg);
6775 		g_free (parent_name);
6776 		g_free (details);
6777 		g_object_unref (parent);
6778 		g_object_unref (info);
6779 		g_object_unref (destination);
6780 
6781 		return;
6782 	}
6783 
6784 	g_object_unref (info);
6785 	g_object_unref (destination);
6786 
6787 	/* file exists and it's a directory or unknown -> skip */
6788 
6789 	overwrite_data_skip_current (odata);
6790 	_fr_window_ask_overwrite_dialog (odata);
6791 }
6792 
6793 
6794 static void
_fr_window_ask_overwrite_dialog(OverwriteData * odata)6795 _fr_window_ask_overwrite_dialog (OverwriteData *odata)
6796 {
6797 	gboolean perform_extraction = TRUE;
6798 	gboolean check_file_existence;
6799 
6800 	check_file_existence = (odata->edata->overwrite == FR_OVERWRITE_ASK) || (odata->edata->overwrite == FR_OVERWRITE_NO);
6801 	if (check_file_existence && (odata->current_file != NULL)) {
6802 		const char *base_name;
6803 		GFile      *destination;
6804 
6805 		base_name = _g_path_get_relative_basename_safe ((char *) odata->current_file->data, odata->edata->base_dir, odata->edata->junk_paths);
6806 		if (base_name != NULL) {
6807 			destination = g_file_get_child (odata->edata->destination, base_name);
6808 			g_file_query_info_async (destination,
6809 						 G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
6810 						 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
6811 						 G_PRIORITY_DEFAULT,
6812 						 odata->window->priv->cancellable,
6813 						 query_info_ready_for_overwrite_dialog_cb,
6814 						 odata);
6815 
6816 			return;
6817 		}
6818 		else {
6819 			overwrite_data_skip_current (odata);
6820 			_fr_window_ask_overwrite_dialog (odata);
6821 			return;
6822 		}
6823 	}
6824 
6825 	if (odata->edata->file_list == NULL)
6826 		perform_extraction = FALSE;
6827 
6828 	if (perform_extraction) {
6829 		/* speed optimization: passing NULL when extracting all the
6830 		 * files is faster if the command supports the
6831 		 * propCanExtractAll property. */
6832 		if (odata->extract_all) {
6833 			_g_string_list_free (odata->edata->file_list);
6834 			odata->edata->file_list = NULL;
6835 		}
6836 		odata->edata->overwrite = FR_OVERWRITE_YES;
6837 
6838 		_fr_window_archive_extract_from_edata (odata->window, odata->edata);
6839 	}
6840 	else {
6841 		GtkWidget *d;
6842 
6843 		d = _gtk_message_dialog_new (GTK_WINDOW (odata->window),
6844 					     0,
6845 					     _("Extraction not performed"),
6846 					     NULL,
6847 					     _GTK_LABEL_CLOSE, GTK_RESPONSE_OK,
6848 					     NULL);
6849 		gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK);
6850 		fr_window_show_error_dialog (odata->window, d, GTK_WINDOW (odata->window), _("Extraction not performed"));
6851 
6852 		fr_window_batch_stop (odata->window);
6853 		fr_window_dnd_extraction_finished (odata->window, TRUE);
6854 	}
6855 
6856 	overwrite_data_free (odata);
6857 }
6858 
6859 
6860 static gboolean
archive_is_encrypted(FrWindow * window,GList * file_list)6861 archive_is_encrypted (FrWindow *window,
6862 		      GList    *file_list)
6863 {
6864 	gboolean encrypted = FALSE;
6865 
6866 	if (file_list == NULL) {
6867 		int i;
6868 
6869 		for (i = 0; ! encrypted && i < window->archive->files->len; i++) {
6870 			FileData *fdata = g_ptr_array_index (window->archive->files, i);
6871 
6872 			if (fdata->encrypted)
6873 				encrypted = TRUE;
6874 		}
6875 	}
6876 	else {
6877 		GList *scan;
6878 
6879 		for (scan = file_list; ! encrypted && scan; scan = scan->next) {
6880 			char     *filename = scan->data;
6881 			FileData *fdata;
6882 
6883 			fdata = g_hash_table_lookup (window->archive->files_hash, filename);
6884 			g_return_val_if_fail (fdata != NULL, FALSE);
6885 
6886 			if (fdata->encrypted)
6887 				encrypted = TRUE;
6888 		}
6889 	}
6890 
6891 	return encrypted;
6892 }
6893 
6894 
6895 /* ask some questions to the user before calling _fr_window_archive_extract_from_edata */
6896 static void
_fr_window_archive_extract_from_edata_maybe(FrWindow * window,ExtractData * edata)6897 _fr_window_archive_extract_from_edata_maybe (FrWindow    *window,
6898 					     ExtractData *edata)
6899 {
6900 	gboolean  do_not_extract = FALSE;
6901 	GError   *error = NULL;
6902 
6903 	if (archive_is_encrypted (window, edata->file_list) && (window->priv->password == NULL)) {
6904 		dlg_ask_password (window);
6905 		return;
6906 	}
6907 
6908 	if (! _g_file_query_is_dir (edata->destination)) {
6909 
6910 		/* There is nothing to ask if the destination doesn't exist. */
6911 		if (edata->overwrite == FR_OVERWRITE_ASK)
6912 			edata->overwrite = FR_OVERWRITE_YES;
6913 
6914 		if (! ForceDirectoryCreation && ! edata->avoid_tarbombs) {
6915 			GtkWidget *d;
6916 			int        r;
6917 			char      *folder_name;
6918 			char      *msg;
6919 
6920 			folder_name = _g_file_get_display_basename (edata->destination);
6921 			msg = g_strdup_printf (_("Destination folder “%s” does not exist.\n\nDo you want to create it?"), folder_name);
6922 			g_free (folder_name);
6923 
6924 			d = _gtk_message_dialog_new (GTK_WINDOW (window),
6925 						     GTK_DIALOG_MODAL,
6926 						     msg,
6927 						     NULL,
6928 						     _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL,
6929 						     _("Create _Folder"), GTK_RESPONSE_YES,
6930 						     NULL);
6931 
6932 			gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_YES);
6933 			r = gtk_dialog_run (GTK_DIALOG (d));
6934 			gtk_widget_destroy (GTK_WIDGET (d));
6935 
6936 			g_free (msg);
6937 
6938 			if (r != GTK_RESPONSE_YES)
6939 				do_not_extract = TRUE;
6940 		}
6941 
6942 		if (! do_not_extract && ! _g_file_make_directory_tree (edata->destination, 0755, &error)) {
6943 			GtkWidget *d;
6944 			char      *details;
6945 
6946 			details = g_strdup_printf (_("Could not create the destination folder: %s."), error->message);
6947 			d = _gtk_error_dialog_new (GTK_WINDOW (window),
6948 						   0,
6949 						   NULL,
6950 						   _("Extraction not performed"),
6951 						   "%s",
6952 						   details);
6953 			g_clear_error (&error);
6954 			fr_window_show_error_dialog (window, d, GTK_WINDOW (window), details);
6955 			fr_window_batch_stop (window);
6956 			fr_window_dnd_extraction_finished (window, TRUE);
6957 
6958 			g_free (details);
6959 
6960 			return;
6961 		}
6962 	}
6963 
6964 	if (do_not_extract) {
6965 		GtkWidget *d;
6966 
6967 		d = _gtk_message_dialog_new (GTK_WINDOW (window),
6968 					     0,
6969 					     _("Extraction not performed"),
6970 					     NULL,
6971 					     _GTK_LABEL_CLOSE, GTK_RESPONSE_OK,
6972 					     NULL);
6973 		gtk_dialog_set_default_response (GTK_DIALOG (d), GTK_RESPONSE_OK);
6974 		fr_window_show_error_dialog (window, d, GTK_WINDOW (window), _("Extraction not performed"));
6975 		fr_window_batch_stop (window);
6976 		fr_window_dnd_extraction_finished (window, TRUE);
6977 
6978 		return;
6979 	}
6980 
6981 	if (edata->overwrite == FR_OVERWRITE_ASK) {
6982 		OverwriteData *odata;
6983 
6984 		odata = overwrite_data_new (window);
6985 		odata->edata = edata;
6986 		odata->extract_all = (edata->file_list == NULL) || (g_list_length (edata->file_list) == window->archive->files->len);
6987 		if (edata->file_list == NULL)
6988 			edata->file_list = fr_window_get_file_list (window);
6989 		odata->current_file = odata->edata->file_list;
6990 
6991 		_fr_window_ask_overwrite_dialog (odata);
6992 	}
6993 	else
6994 		_fr_window_archive_extract_from_edata (window, edata);
6995 }
6996 
6997 
6998 void
fr_window_archive_extract(FrWindow * window,GList * file_list,GFile * destination,const char * base_dir,gboolean skip_older,FrOverwrite overwrite,gboolean junk_paths,gboolean ask_to_open_destination)6999 fr_window_archive_extract (FrWindow    *window,
7000 			   GList       *file_list,
7001 			   GFile       *destination,
7002 			   const char  *base_dir,
7003 			   gboolean     skip_older,
7004 			   FrOverwrite  overwrite,
7005 			   gboolean     junk_paths,
7006 			   gboolean     ask_to_open_destination)
7007 {
7008 	ExtractData *edata;
7009 
7010 	edata = extract_data_new (window,
7011 				  file_list,
7012 				  destination,
7013 				  base_dir,
7014 				  skip_older,
7015 				  overwrite,
7016 				  junk_paths,
7017 				  ask_to_open_destination,
7018 				  FALSE);
7019 
7020 	fr_window_set_current_action (window,
7021 				      FR_BATCH_ACTION_EXTRACT,
7022 				      edata,
7023 				      (GFreeFunc) extract_data_free);
7024 
7025 	_fr_window_archive_extract_from_edata_maybe (window, edata);
7026 }
7027 
7028 
7029 /* -- fr_window_archive_extract_here -- */
7030 
7031 
7032 #define MIN_TOPLEVEL_ITEMS_FOR_A_TARBOMB 2
7033 
7034 
7035 static gboolean
_archive_extraction_generates_a_tarbomb(FrArchive * archive)7036 _archive_extraction_generates_a_tarbomb (FrArchive *archive)
7037 {
7038 	gboolean    tarbomb = FALSE;
7039 	GHashTable *names_hash;
7040 	int         n_toplevel_items, i;
7041 
7042 	names_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
7043 	n_toplevel_items = 0;
7044 	for (i = 0; ! tarbomb && (i < archive->files->len); i++) {
7045 		FileData *fdata = g_ptr_array_index (archive->files, i);
7046 		char     *second_separator;
7047 		char     *name = NULL;
7048 		gboolean  name_created;
7049 
7050 		if ((fdata->full_path == NULL) || (fdata->full_path[0] == '\0'))
7051 			continue;
7052 
7053 		second_separator = strchr (fdata->full_path + 1 /* skip the first separator */, '/');
7054 		if (second_separator != NULL) {
7055 			name = g_strndup (fdata->full_path, second_separator - fdata->full_path);
7056 			name_created = TRUE;
7057 		}
7058 		else {
7059 			name = fdata->full_path;
7060 			name_created = FALSE;
7061 		}
7062 
7063 		if (g_hash_table_lookup (names_hash, name) == NULL) {
7064 			g_hash_table_insert (names_hash, name_created ? name : g_strdup (name), GINT_TO_POINTER (1));
7065 			n_toplevel_items++;
7066 			if (n_toplevel_items >= MIN_TOPLEVEL_ITEMS_FOR_A_TARBOMB)
7067 				tarbomb = TRUE;
7068 		}
7069 		else if (name_created)
7070 			g_free (name);
7071 	}
7072 	g_hash_table_destroy (names_hash);
7073 
7074 	return tarbomb;
7075 }
7076 
7077 
7078 static GFile *
_get_destination_to_avoid_tarbomb(GFile * file)7079 _get_destination_to_avoid_tarbomb (GFile *file)
7080 {
7081 	GFile      *directory;
7082 	char       *name;
7083 	const char *ext;
7084 	char       *new_name;
7085 	GFile      *destination;
7086 
7087 	directory = g_file_get_parent (file);
7088 	name = g_file_get_basename (file);
7089 	ext = get_archive_filename_extension (name);
7090 	if (ext == NULL)
7091 		/* if no extension is present add a suffix to the name... */
7092 		new_name = g_strconcat (name, "_FILES", NULL);
7093 	else
7094 		/* ...else use the name without the extension */
7095 		new_name = g_strndup (name, strlen (name) - strlen (ext));
7096 	destination = g_file_get_child (directory, new_name);
7097 
7098 	g_free (new_name);
7099 	g_free (name);
7100 	g_object_unref (directory);
7101 
7102 	return destination;
7103 }
7104 
7105 
7106 void
fr_window_archive_extract_here(FrWindow * window,gboolean skip_older,gboolean overwrite,gboolean junk_paths)7107 fr_window_archive_extract_here (FrWindow   *window,
7108 				gboolean    skip_older,
7109 				gboolean    overwrite,
7110 				gboolean    junk_paths)
7111 {
7112 	GFile       *destination;
7113 	ExtractData *edata;
7114 
7115 	if (_archive_extraction_generates_a_tarbomb (window->archive))
7116 		destination = _get_destination_to_avoid_tarbomb (fr_archive_get_file (window->archive));
7117 	else
7118 		destination = g_file_get_parent (fr_archive_get_file (window->archive));
7119 
7120 	edata = extract_data_new (window,
7121 				  NULL,
7122 				  destination,
7123 				  NULL,
7124 				  skip_older,
7125 				  overwrite,
7126 				  junk_paths,
7127 				  _fr_window_get_ask_to_open_destination (window),
7128 				  TRUE);
7129 
7130 	fr_window_set_current_action (window,
7131 				      FR_BATCH_ACTION_EXTRACT,
7132 				      edata,
7133 				      (GFreeFunc) extract_data_free);
7134 
7135 	_fr_window_archive_extract_from_edata_maybe (window, edata);
7136 
7137 	g_object_unref (destination);
7138 }
7139 
7140 
7141 /* -- fr_window_archive_test -- */
7142 
7143 
7144 static void
archive_test_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7145 archive_test_ready_cb (GObject      *source_object,
7146 		       GAsyncResult *result,
7147 		       gpointer      user_data)
7148 {
7149 	FrWindow *window = user_data;
7150 	GError   *error = NULL;
7151 
7152 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
7153 	_archive_operation_completed (window, FR_ACTION_TESTING_ARCHIVE, error);
7154 
7155 	_g_error_free (error);
7156 }
7157 
7158 
7159 void
fr_window_archive_test(FrWindow * window)7160 fr_window_archive_test (FrWindow *window)
7161 {
7162 	_archive_operation_started (window, FR_ACTION_TESTING_ARCHIVE);
7163 	fr_window_set_current_action (window,
7164 					    FR_BATCH_ACTION_TEST,
7165 					    NULL,
7166 					    NULL);
7167 	fr_archive_test (window->archive,
7168 			 window->priv->password,
7169 			 window->priv->cancellable,
7170 			 archive_test_ready_cb,
7171 			 window);
7172 }
7173 
7174 
7175 void
fr_window_set_password(FrWindow * window,const char * password)7176 fr_window_set_password (FrWindow   *window,
7177 			const char *password)
7178 {
7179 	g_return_if_fail (window != NULL);
7180 
7181 	if (window->priv->password == password)
7182 		return;
7183 
7184 	if (window->priv->password != NULL) {
7185 		g_free (window->priv->password);
7186 		window->priv->password = NULL;
7187 	}
7188 
7189 	if ((password != NULL) && (password[0] != '\0'))
7190 		window->priv->password = g_strdup (password);
7191 }
7192 
7193 
7194 void
fr_window_set_password_for_second_archive(FrWindow * window,const char * password)7195 fr_window_set_password_for_second_archive (FrWindow   *window,
7196 					   const char *password)
7197 {
7198 	g_return_if_fail (window != NULL);
7199 
7200 	if (window->priv->second_password != NULL) {
7201 		g_free (window->priv->second_password);
7202 		window->priv->second_password = NULL;
7203 	}
7204 
7205 	if ((password != NULL) && (password[0] != '\0'))
7206 		window->priv->second_password = g_strdup (password);
7207 }
7208 
7209 
7210 const char *
fr_window_get_password(FrWindow * window)7211 fr_window_get_password (FrWindow *window)
7212 {
7213 	g_return_val_if_fail (window != NULL, NULL);
7214 
7215 	return window->priv->password;
7216 }
7217 
7218 
7219 const char *
fr_window_get_password_for_second_archive(FrWindow * window)7220 fr_window_get_password_for_second_archive (FrWindow *window)
7221 {
7222 	g_return_val_if_fail (window != NULL, NULL);
7223 
7224 	return window->priv->second_password;
7225 }
7226 
7227 
7228 void
fr_window_set_encrypt_header(FrWindow * window,gboolean encrypt_header)7229 fr_window_set_encrypt_header (FrWindow *window,
7230 			      gboolean  encrypt_header)
7231 {
7232 	g_return_if_fail (window != NULL);
7233 
7234 	window->priv->encrypt_header = encrypt_header;
7235 }
7236 
7237 
7238 gboolean
fr_window_get_encrypt_header(FrWindow * window)7239 fr_window_get_encrypt_header (FrWindow *window)
7240 {
7241 	return window->priv->encrypt_header;
7242 }
7243 
7244 
7245 void
fr_window_set_compression(FrWindow * window,FrCompression compression)7246 fr_window_set_compression (FrWindow      *window,
7247 			   FrCompression  compression)
7248 {
7249 	g_return_if_fail (window != NULL);
7250 
7251 	window->priv->compression = compression;
7252 }
7253 
7254 
7255 FrCompression
fr_window_get_compression(FrWindow * window)7256 fr_window_get_compression (FrWindow *window)
7257 {
7258 	return window->priv->compression;
7259 }
7260 
7261 
7262 void
fr_window_set_volume_size(FrWindow * window,guint volume_size)7263 fr_window_set_volume_size (FrWindow *window,
7264 			   guint     volume_size)
7265 {
7266 	g_return_if_fail (window != NULL);
7267 
7268 	window->priv->volume_size = volume_size;
7269 }
7270 
7271 
7272 guint
fr_window_get_volume_size(FrWindow * window)7273 fr_window_get_volume_size (FrWindow *window)
7274 {
7275 	return window->priv->volume_size;
7276 }
7277 
7278 
7279 void
fr_window_go_to_location(FrWindow * window,const char * path,gboolean force_update)7280 fr_window_go_to_location (FrWindow   *window,
7281 			  const char *path,
7282 			  gboolean    force_update)
7283 {
7284 	char *dir;
7285 
7286 	g_return_if_fail (window != NULL);
7287 	g_return_if_fail (path != NULL);
7288 
7289 	if (force_update) {
7290 		g_free (window->priv->last_location);
7291 		window->priv->last_location = NULL;
7292 	}
7293 
7294 	if (path[strlen (path) - 1] != '/')
7295 		dir = g_strconcat (path, "/", NULL);
7296 	else
7297 		dir = g_strdup (path);
7298 
7299 	if ((window->priv->last_location == NULL) || (strcmp (window->priv->last_location, dir) != 0)) {
7300 		g_free (window->priv->last_location);
7301 		window->priv->last_location = dir;
7302 
7303 		fr_window_history_add (window, dir);
7304 		fr_window_update_file_list (window, TRUE);
7305 		fr_window_update_current_location (window);
7306 	}
7307 	else
7308 		g_free (dir);
7309 }
7310 
7311 
7312 const char *
fr_window_get_current_location(FrWindow * window)7313 fr_window_get_current_location (FrWindow *window)
7314 {
7315 	if (window->priv->history_current == NULL) {
7316 		fr_window_history_add (window, "/");
7317 		return window->priv->history_current->data;
7318 	}
7319 	else
7320 		return (const char*) window->priv->history_current->data;
7321 }
7322 
7323 
7324 void
fr_window_go_up_one_level(FrWindow * window)7325 fr_window_go_up_one_level (FrWindow *window)
7326 {
7327 	char *parent_dir;
7328 
7329 	g_return_if_fail (window != NULL);
7330 
7331 	parent_dir = get_parent_dir (fr_window_get_current_location (window));
7332 	fr_window_go_to_location (window, parent_dir, FALSE);
7333 	g_free (parent_dir);
7334 }
7335 
7336 
7337 void
fr_window_go_back(FrWindow * window)7338 fr_window_go_back (FrWindow *window)
7339 {
7340 	g_return_if_fail (window != NULL);
7341 
7342 	if (window->priv->history == NULL)
7343 		return;
7344 	if (window->priv->history_current == NULL)
7345 		return;
7346 	if (window->priv->history_current->next == NULL)
7347 		return;
7348 	window->priv->history_current = window->priv->history_current->next;
7349 
7350 	fr_window_go_to_location (window, window->priv->history_current->data, FALSE);
7351 }
7352 
7353 
7354 void
fr_window_go_forward(FrWindow * window)7355 fr_window_go_forward (FrWindow *window)
7356 {
7357 	g_return_if_fail (window != NULL);
7358 
7359 	if (window->priv->history == NULL)
7360 		return;
7361 	if (window->priv->history_current == NULL)
7362 		return;
7363 	if (window->priv->history_current->prev == NULL)
7364 		return;
7365 	window->priv->history_current = window->priv->history_current->prev;
7366 
7367 	fr_window_go_to_location (window, window->priv->history_current->data, FALSE);
7368 }
7369 
7370 
7371 void
fr_window_set_list_mode(FrWindow * window,FrWindowListMode list_mode)7372 fr_window_set_list_mode (FrWindow         *window,
7373 			 FrWindowListMode  list_mode)
7374 {
7375 	g_return_if_fail (window != NULL);
7376 
7377 	if (list_mode == window->priv->list_mode)
7378 		return;
7379 
7380 	window->priv->list_mode = window->priv->last_list_mode = list_mode;
7381 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT) {
7382 		fr_window_history_clear (window);
7383 		fr_window_history_add (window, "/");
7384 	}
7385 
7386 	g_settings_set_enum (window->priv->settings_listing, PREF_LISTING_LIST_MODE, window->priv->last_list_mode);
7387 	g_settings_set_boolean (window->priv->settings_listing, PREF_LISTING_SHOW_PATH, (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT));
7388 
7389 	fr_window_update_file_list (window, TRUE);
7390 	fr_window_update_dir_tree (window);
7391 	fr_window_update_current_location (window);
7392 }
7393 
7394 
7395 GtkTreeModel *
fr_window_get_list_store(FrWindow * window)7396 fr_window_get_list_store (FrWindow *window)
7397 {
7398 	return GTK_TREE_MODEL (window->priv->list_store);
7399 }
7400 
7401 
7402 void
fr_window_find(FrWindow * window,gboolean active)7403 fr_window_find (FrWindow *window,
7404 		gboolean  active)
7405 {
7406 	gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (window->priv->filter_bar), active);
7407 	if (active) {
7408 		window->priv->filter_mode = TRUE;
7409 		gtk_widget_show (window->priv->filter_bar);
7410 		gtk_widget_hide (window->priv->location_bar);
7411 	}
7412 	else {
7413 		window->priv->filter_mode = FALSE;
7414 		window->priv->list_mode = window->priv->last_list_mode;
7415 
7416 		gtk_entry_set_text (GTK_ENTRY (window->priv->filter_entry), "");
7417 		gtk_widget_hide (window->priv->filter_bar);
7418 
7419 		gtk_list_store_clear (window->priv->list_store);
7420 
7421 		fr_window_update_columns_visibility (window);
7422 		fr_window_update_file_list (window, TRUE);
7423 		fr_window_update_dir_tree (window);
7424 		fr_window_update_current_location (window);
7425 		fr_window_go_to_location (window, gtk_entry_get_text (GTK_ENTRY (window->priv->location_entry)), FALSE);
7426 	}
7427 }
7428 
7429 
7430 void
fr_window_select_all(FrWindow * window)7431 fr_window_select_all (FrWindow *window)
7432 {
7433 	gtk_tree_selection_select_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
7434 }
7435 
7436 
7437 void
fr_window_unselect_all(FrWindow * window)7438 fr_window_unselect_all (FrWindow *window)
7439 {
7440 	gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (window->priv->list_view)));
7441 }
7442 
7443 
7444 void
fr_window_stop(FrWindow * window)7445 fr_window_stop (FrWindow *window)
7446 {
7447 	if (window->priv->stoppable && (window->priv->activity_ref > 0))
7448 		g_cancellable_cancel (window->priv->cancellable);
7449 }
7450 
7451 
7452 void
fr_window_action_new_archive(FrWindow * window)7453 fr_window_action_new_archive (FrWindow *window)
7454 {
7455 	GtkWidget *dialog;
7456 
7457 	if (fr_window_present_dialog_if_created (window, "new_archive"))
7458 		return;
7459 
7460 	dialog = fr_new_archive_dialog_new (_("New Archive"),
7461 					    GTK_WINDOW (window),
7462 					    FR_NEW_ARCHIVE_ACTION_NEW_MANY_FILES,
7463 					    fr_window_get_open_default_dir (window),
7464 					    NULL,
7465 					    NULL);
7466 	if ((fr_window_archive_is_present (window) && ! fr_window_is_batch_mode (window) ? NULL : GTK_WINDOW (window)))
7467 		gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
7468 	g_signal_connect (G_OBJECT (dialog),
7469 			  "response",
7470 			  G_CALLBACK (new_archive_dialog_response_cb),
7471 			  window);
7472 	fr_window_set_dialog (window, "new_archive", dialog);
7473 	gtk_window_present (GTK_WINDOW (dialog));
7474 }
7475 
7476 
7477 /* -- fr_window_action_save_as -- */
7478 
7479 
7480 typedef struct {
7481 	FrWindow  *window;
7482 	FrArchive *new_archive;
7483 	GFile     *file;
7484 	char      *mime_type;
7485 	char      *password;
7486 	gboolean   encrypt_header;
7487 	guint      volume_size;
7488 	GFile     *temp_extraction_dir;
7489 } ConvertData;
7490 
7491 
7492 static ConvertData *
convert_data_new(GFile * file,const char * mime_type,const char * password,gboolean encrypt_header,guint volume_size)7493 convert_data_new (GFile      *file,
7494 		  const char *mime_type,
7495 		  const char *password,
7496 		  gboolean    encrypt_header,
7497 	  	  guint       volume_size)
7498 {
7499 	ConvertData *cdata;
7500 
7501 	cdata = g_new0 (ConvertData, 1);
7502 	cdata->file = _g_object_ref (file);
7503 	if (mime_type != NULL)
7504 		cdata->mime_type = g_strdup (mime_type);
7505 	if (password != NULL)
7506 		cdata->password = g_strdup (password);
7507 	cdata->encrypt_header = encrypt_header;
7508 	cdata->volume_size = volume_size;
7509 	cdata->temp_extraction_dir = _g_file_get_temp_work_dir (NULL);
7510 
7511 	return cdata;
7512 }
7513 
7514 
7515 static void
convert_data_free(ConvertData * cdata)7516 convert_data_free (ConvertData *cdata)
7517 {
7518 	if (cdata == NULL)
7519 		return;
7520 	_g_file_remove_directory (cdata->temp_extraction_dir, NULL, NULL);
7521 	_g_object_unref (cdata->temp_extraction_dir);
7522 	_g_object_unref (cdata->file);
7523 	_g_object_unref (cdata->new_archive);
7524 	g_free (cdata->mime_type);
7525 	g_free (cdata->password);
7526 	g_free (cdata);
7527 }
7528 
7529 
7530 static void
archive_add_ready_for_conversion_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7531 archive_add_ready_for_conversion_cb (GObject      *source_object,
7532 				     GAsyncResult *result,
7533 				     gpointer      user_data)
7534 {
7535 	ConvertData *cdata = user_data;
7536 	FrWindow    *window = cdata->window;
7537 	GError      *error = NULL;
7538 
7539 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
7540 
7541 	_fr_window_stop_activity_mode (window);
7542 	close_progress_dialog (window, FALSE);
7543 
7544 	if (error != NULL) {
7545 		_handle_archive_operation_error (window,
7546 						 cdata->new_archive,
7547 						 FR_ACTION_ADDING_FILES,
7548 						 error,
7549 						 NULL,
7550 						 NULL);
7551 		fr_window_batch_stop (window);
7552 		g_error_free (error);
7553 		return;
7554 	}
7555 
7556 	fr_window_show_confirmation_dialog_with_open_archive (window);
7557 	fr_window_batch_exec_next_action (window);
7558 }
7559 
7560 
7561 static void
_convertion_completed_with_error(FrWindow * window,FrAction action,GError * error)7562 _convertion_completed_with_error (FrWindow *window,
7563 				  FrAction  action,
7564 				  GError   *error)
7565 {
7566 	gboolean opens_dialog;
7567 
7568 	g_return_if_fail (error != NULL);
7569 
7570 #ifdef DEBUG
7571 	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
7572 #endif
7573 
7574 	_fr_window_stop_activity_mode (window);
7575 	close_progress_dialog (window, FALSE);
7576 
7577 	_handle_archive_operation_error (window, window->archive, action, error, NULL, &opens_dialog);
7578 	if (opens_dialog)
7579 		return;
7580 
7581 	_g_clear_object (&window->priv->saving_file);
7582 	fr_window_batch_stop (window);
7583 }
7584 
7585 
7586 static void
archive_extraction_ready_for_convertion_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7587 archive_extraction_ready_for_convertion_cb (GObject      *source_object,
7588 					    GAsyncResult *result,
7589 					    gpointer      user_data)
7590 {
7591 	ConvertData *cdata = user_data;
7592 	FrWindow    *window = cdata->window;
7593 	GList       *list;
7594 	GError      *error = NULL;
7595 
7596 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
7597 		_convertion_completed_with_error (window, FR_ACTION_EXTRACTING_FILES, error);
7598 		return;
7599 	}
7600 
7601 	list = g_list_prepend (NULL, cdata->temp_extraction_dir);
7602 	fr_archive_add_files (cdata->new_archive,
7603 			      list,
7604 			      cdata->temp_extraction_dir,
7605 			      NULL,
7606 			      FALSE,
7607 			      FALSE,
7608 			      cdata->password,
7609 			      cdata->encrypt_header,
7610 			      window->priv->compression,
7611 			      cdata->volume_size,
7612 			      window->priv->cancellable,
7613 			      archive_add_ready_for_conversion_cb,
7614 			      cdata);
7615 
7616 	g_list_free (list);
7617 }
7618 
7619 
7620 static void
fr_window_archive_save_as(FrWindow * window,GFile * file,const char * mime_type,const char * password,gboolean encrypt_header,guint volume_size)7621 fr_window_archive_save_as (FrWindow   *window,
7622 			   GFile      *file,
7623 			   const char *mime_type,
7624 			   const char *password,
7625 			   gboolean    encrypt_header,
7626 			   guint       volume_size)
7627 {
7628 	FrArchive   *new_archive;
7629 	ConvertData *cdata;
7630 
7631 	g_return_if_fail (window != NULL);
7632 	g_return_if_fail (file != NULL);
7633 	g_return_if_fail (window->archive != NULL);
7634 
7635 	/* create the new archive */
7636 
7637 	new_archive = fr_archive_create (file, mime_type);
7638 	if (new_archive == NULL) {
7639 		GtkWidget *d;
7640 		char      *utf8_name;
7641 		char      *message;
7642 
7643 		utf8_name = _g_file_get_display_basename (file);
7644 		message = g_strdup_printf (_("Could not save the archive “%s”"), utf8_name);
7645 		g_free (utf8_name);
7646 
7647 		d = _gtk_error_dialog_new (GTK_WINDOW (window),
7648 					   GTK_DIALOG_DESTROY_WITH_PARENT,
7649 					   NULL,
7650 					   message,
7651 					   "%s",
7652 					   _("Archive type not supported."));
7653 		gtk_dialog_run (GTK_DIALOG (d));
7654 		gtk_widget_destroy (d);
7655 
7656 		g_free (message);
7657 
7658 		return;
7659 	}
7660 
7661 	cdata = convert_data_new (file, mime_type, password, encrypt_header, volume_size);
7662 	cdata->window = window;
7663 	cdata->new_archive = new_archive;
7664 
7665 	_archive_operation_started (window, FR_ACTION_CREATING_ARCHIVE);
7666 	fr_window_set_current_action (window,
7667 					    FR_BATCH_ACTION_SAVE_AS,
7668 					    cdata,
7669 					    (GFreeFunc) convert_data_free);
7670 
7671 	g_signal_connect (cdata->new_archive,
7672 			  "progress",
7673 			  G_CALLBACK (fr_archive_progress_cb),
7674 			  window);
7675 	g_signal_connect (cdata->new_archive,
7676 			  "message",
7677 			  G_CALLBACK (fr_archive_message_cb),
7678 			  window);
7679 	g_signal_connect (cdata->new_archive,
7680 			  "start",
7681 			  G_CALLBACK (fr_archive_start_cb),
7682 			  window);
7683 	g_signal_connect (cdata->new_archive,
7684 			  "stoppable",
7685 			  G_CALLBACK (fr_archive_stoppable_cb),
7686 			  window);
7687 	g_signal_connect (cdata->new_archive,
7688 			  "working-archive",
7689 			  G_CALLBACK (fr_window_working_archive_cb),
7690 			  window);
7691 
7692 	_g_object_unref (window->priv->saving_file);
7693 	window->priv->saving_file = g_object_ref (cdata->file);
7694 
7695 	fr_archive_action_started (window->archive, FR_ACTION_EXTRACTING_FILES);
7696 	fr_archive_extract (window->archive,
7697 			    NULL,
7698 			    cdata->temp_extraction_dir,
7699 			    NULL,
7700 			    FALSE,
7701 			    TRUE,
7702 			    FALSE,
7703 			    window->priv->password,
7704 			    window->priv->cancellable,
7705 			    archive_extraction_ready_for_convertion_cb,
7706 			    cdata);
7707 }
7708 
7709 
7710 static void
save_as_archive_dialog_response_cb(GtkDialog * dialog,int response,gpointer user_data)7711 save_as_archive_dialog_response_cb (GtkDialog *dialog,
7712 				    int        response,
7713 				    gpointer   user_data)
7714 {
7715 	FrWindow   *window = user_data;
7716 	GFile      *file;
7717 	const char *mime_type;
7718 	const char *password;
7719 	gboolean    encrypt_header;
7720 	int         volume_size;
7721 	GSettings  *settings;
7722 
7723 	if ((response == GTK_RESPONSE_CANCEL) || (response == GTK_RESPONSE_DELETE_EVENT)) {
7724 		gtk_widget_destroy (GTK_WIDGET (dialog));
7725 		_archive_operation_cancelled (window, FR_ACTION_CREATING_ARCHIVE);
7726 		return;
7727 	}
7728 
7729 	if (response != GTK_RESPONSE_OK)
7730 		return;
7731 
7732 	file = fr_new_archive_dialog_get_file (FR_NEW_ARCHIVE_DIALOG (dialog), &mime_type);
7733 	if (file == NULL)
7734 		return;
7735 
7736 	password = fr_new_archive_dialog_get_password (FR_NEW_ARCHIVE_DIALOG (dialog));
7737 	encrypt_header = fr_new_archive_dialog_get_encrypt_header (FR_NEW_ARCHIVE_DIALOG (dialog));
7738 	volume_size = fr_new_archive_dialog_get_volume_size (FR_NEW_ARCHIVE_DIALOG (dialog));
7739 
7740 	settings = g_settings_new (FILE_ROLLER_SCHEMA_NEW);
7741 	g_settings_set_int (settings, PREF_NEW_VOLUME_SIZE, volume_size);
7742 	g_object_unref (settings);
7743 
7744 	fr_window_archive_save_as (window, file, mime_type, password, encrypt_header, volume_size);
7745 
7746 	gtk_widget_destroy (GTK_WIDGET (dialog));
7747 	g_object_unref (file);
7748 }
7749 
7750 
7751 void
fr_window_action_save_as(FrWindow * window)7752 fr_window_action_save_as (FrWindow *window)
7753 {
7754 	char      *archive_name;
7755 	GtkWidget *dialog;
7756 
7757 	archive_name = NULL;
7758 	if (window->priv->archive_file != NULL) {
7759 		GFileInfo *info;
7760 
7761 		info = g_file_query_info (window->priv->archive_file,
7762 					  G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
7763 					  0, NULL, NULL);
7764 
7765 		if (info != NULL) {
7766 			archive_name = g_strdup (g_file_info_get_display_name (info));
7767 			g_object_unref (info);
7768 		}
7769 	}
7770 
7771 	dialog = fr_new_archive_dialog_new (_("Save"),
7772 					    GTK_WINDOW (window),
7773 					    FR_NEW_ARCHIVE_ACTION_SAVE_AS,
7774 					    fr_window_get_open_default_dir (window),
7775 					    archive_name,
7776 					    window->priv->archive_file);
7777 	gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
7778 	g_signal_connect (G_OBJECT (dialog),
7779 			  "response",
7780 			  G_CALLBACK (save_as_archive_dialog_response_cb),
7781 			  window);
7782 	gtk_window_present (GTK_WINDOW (dialog));
7783 
7784 	g_free (archive_name);
7785 }
7786 
7787 
7788 /* -- fr_window_archive_encrypt -- */
7789 
7790 
7791 typedef struct {
7792 	FrWindow  *window;
7793 	char      *password;
7794 	gboolean   encrypt_header;
7795 	GFile     *temp_extraction_dir;
7796 	GFile     *temp_new_file;
7797 	FrArchive *new_archive;
7798 } EncryptData;
7799 
7800 
7801 static EncryptData *
encrypt_data_new(FrWindow * window,const char * password,gboolean encrypt_header)7802 encrypt_data_new (FrWindow   *window,
7803 		  const char *password,
7804 		  gboolean    encrypt_header)
7805 {
7806 	EncryptData *edata;
7807 
7808 	edata = g_new0 (EncryptData, 1);
7809 	edata->window = window;
7810 	if (password != NULL)
7811 		edata->password = g_strdup (password);
7812 	edata->encrypt_header = encrypt_header;
7813 	edata->temp_extraction_dir = _g_file_get_temp_work_dir (NULL);
7814 
7815 	return edata;
7816 }
7817 
7818 
7819 static void
encrypt_data_free(EncryptData * edata)7820 encrypt_data_free (EncryptData *edata)
7821 {
7822 	if (edata == NULL)
7823 		return;
7824 
7825 	if (edata->temp_new_file != NULL) {
7826 		GFile *parent = g_file_get_parent (edata->temp_new_file);
7827 		if (parent != NULL)
7828 			_g_file_remove_directory (parent, NULL, NULL);
7829 		_g_object_unref (parent);
7830 	}
7831 	_g_object_unref (edata->temp_new_file);
7832 	_g_object_unref (edata->new_archive);
7833 	_g_file_remove_directory (edata->temp_extraction_dir, NULL, NULL);
7834 	_g_object_unref (edata->temp_extraction_dir);
7835 	g_free (edata->password);
7836 	g_free (edata);
7837 }
7838 
7839 
7840 static void
_encrypt_operation_completed_with_error(FrWindow * window,FrAction action,GError * error)7841 _encrypt_operation_completed_with_error (FrWindow *window,
7842 					 FrAction  action,
7843 					 GError   *error)
7844 {
7845 	gboolean opens_dialog;
7846 
7847 	g_return_if_fail (error != NULL);
7848 
7849 #ifdef DEBUG
7850 	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
7851 #endif
7852 
7853 	_fr_window_stop_activity_mode (window);
7854 	_handle_archive_operation_error (window, window->archive, action, error, NULL, &opens_dialog);
7855 	if (opens_dialog)
7856 		return;
7857 
7858 	close_progress_dialog (window, FALSE);
7859 	fr_window_batch_stop (window);
7860 }
7861 
7862 
7863 static void
ecryption_copy_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7864 ecryption_copy_ready_cb (GObject      *source_object,
7865 			 GAsyncResult *result,
7866 			 gpointer      user_data)
7867 {
7868 	EncryptData *edata = user_data;
7869 	FrWindow    *window = edata->window;
7870 	GError      *error = NULL;
7871 
7872 	_fr_window_stop_activity_mode (window);
7873 	close_progress_dialog (window, FALSE);
7874 
7875 	if (! g_file_copy_finish (G_FILE (source_object), result, &error)) {
7876 		_handle_archive_operation_error (window,
7877 						 edata->new_archive,
7878 						 FR_ACTION_CREATING_NEW_ARCHIVE,
7879 						 error,
7880 						 NULL,
7881 						 NULL);
7882 		fr_window_batch_stop (window);
7883 
7884 		g_error_free (error);
7885 		return;
7886 	}
7887 
7888 	fr_window_set_password (window, edata->password);
7889 	fr_window_set_encrypt_header (window, edata->encrypt_header);
7890 	window->priv->reload_archive = TRUE;
7891 	fr_window_batch_exec_next_action (window);
7892 }
7893 
7894 
7895 static void
encryption_copy_progress_cb(goffset current_num_bytes,goffset total_num_bytes,gpointer user_data)7896 encryption_copy_progress_cb (goffset  current_num_bytes,
7897 			     goffset  total_num_bytes,
7898 			     gpointer user_data)
7899 {
7900 	EncryptData *edata = user_data;
7901 
7902 	fr_archive_progress (edata->new_archive, (double) current_num_bytes / total_num_bytes);
7903 }
7904 
7905 
7906 static void
archive_add_ready_for_encryption_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7907 archive_add_ready_for_encryption_cb (GObject      *source_object,
7908 				     GAsyncResult *result,
7909 				     gpointer      user_data)
7910 {
7911 	EncryptData *edata = user_data;
7912 	FrWindow    *window = edata->window;
7913 	GError      *error = NULL;
7914 
7915 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
7916 		_encrypt_operation_completed_with_error (window, FR_ACTION_ENCRYPTING_ARCHIVE, error);
7917 		return;
7918 	}
7919 
7920 	fr_archive_action_started (window->archive, FR_ACTION_SAVING_REMOTE_ARCHIVE);
7921 	g_file_copy_async (edata->temp_new_file,
7922 			   fr_archive_get_file (window->archive),
7923 			   G_FILE_COPY_OVERWRITE,
7924 			   G_PRIORITY_DEFAULT,
7925 			   window->priv->cancellable,
7926 			   encryption_copy_progress_cb,
7927 			   edata,
7928 			   ecryption_copy_ready_cb,
7929 			   edata);
7930 }
7931 
7932 
7933 static void
archive_extraction_ready_for_encryption_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)7934 archive_extraction_ready_for_encryption_cb (GObject      *source_object,
7935 					    GAsyncResult *result,
7936 					    gpointer      user_data)
7937 {
7938 	EncryptData *edata = user_data;
7939 	FrWindow    *window = edata->window;
7940 	GList       *list;
7941 	GError      *error = NULL;
7942 
7943 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
7944 		_encrypt_operation_completed_with_error (window, FR_ACTION_ENCRYPTING_ARCHIVE, error);
7945 		return;
7946 	}
7947 
7948 	fr_archive_action_started (window->archive, FR_ACTION_ENCRYPTING_ARCHIVE);
7949 
7950 	list = g_list_prepend (NULL, edata->temp_extraction_dir);
7951 	fr_archive_add_files (edata->new_archive,
7952 			      list,
7953 			      edata->temp_extraction_dir,
7954 			      NULL,
7955 			      FALSE,
7956 			      FALSE,
7957 			      edata->password,
7958 			      edata->encrypt_header,
7959 			      window->priv->compression,
7960 			      0,
7961 			      window->priv->cancellable,
7962 			      archive_add_ready_for_encryption_cb,
7963 			      edata);
7964 
7965 	g_list_free (list);
7966 }
7967 
7968 
7969 void
fr_window_archive_encrypt(FrWindow * window,const char * password,gboolean encrypt_header)7970 fr_window_archive_encrypt (FrWindow   *window,
7971 			   const char *password,
7972 			   gboolean    encrypt_header)
7973 {
7974 	EncryptData *edata;
7975 	GFile       *temp_destination_parent;
7976 	GFile       *temp_destination;
7977 	char        *basename;
7978 	GFile       *temp_new_file;
7979 	FrArchive   *new_archive;
7980 
7981 	/* create the new archive */
7982 
7983 	if (g_file_is_native (fr_archive_get_file (window->archive)))
7984 		temp_destination_parent = g_file_get_parent (fr_archive_get_file (window->archive));
7985 	else
7986 		temp_destination_parent = NULL;
7987 	temp_destination = _g_file_get_temp_work_dir (temp_destination_parent);
7988 	basename = g_file_get_basename (fr_archive_get_file (window->archive));
7989 	temp_new_file = g_file_get_child (temp_destination, basename);
7990 
7991 	g_free (basename);
7992 	_g_object_unref (temp_destination_parent);
7993 
7994 	new_archive = fr_archive_create (temp_new_file, fr_archive_get_mime_type (window->archive));
7995 	if (new_archive == NULL) {
7996 		GtkWidget *d;
7997 		char      *utf8_name;
7998 		char      *message;
7999 
8000 		utf8_name = _g_file_get_display_basename (temp_new_file);
8001 		message = g_strdup_printf (_("Could not save the archive “%s”"), utf8_name);
8002 		g_free (utf8_name);
8003 
8004 		d = _gtk_error_dialog_new (GTK_WINDOW (window),
8005 					   GTK_DIALOG_DESTROY_WITH_PARENT,
8006 					   NULL,
8007 					   message,
8008 					   "%s",
8009 					   _("Archive type not supported."));
8010 		gtk_dialog_run (GTK_DIALOG (d));
8011 		gtk_widget_destroy (d);
8012 
8013 		g_free (message);
8014 		g_object_unref (temp_new_file);
8015 
8016 		_g_file_remove_directory (temp_destination, NULL, NULL);
8017 		g_object_unref (temp_destination);
8018 
8019 		return;
8020 	}
8021 
8022 	g_object_unref (temp_destination);
8023 
8024 	edata = encrypt_data_new (window, password, encrypt_header);
8025 	edata->temp_new_file = temp_new_file;
8026 	edata->new_archive = new_archive;
8027 
8028 	g_signal_connect (edata->new_archive,
8029 			  "progress",
8030 			  G_CALLBACK (fr_archive_progress_cb),
8031 			  window);
8032 	g_signal_connect (edata->new_archive,
8033 			  "message",
8034 			  G_CALLBACK (fr_archive_message_cb),
8035 			  window);
8036 	g_signal_connect (edata->new_archive,
8037 			  "start",
8038 			  G_CALLBACK (fr_archive_start_cb),
8039 			  window);
8040 	g_signal_connect (edata->new_archive,
8041 			  "stoppable",
8042 			  G_CALLBACK (fr_archive_stoppable_cb),
8043 			  window);
8044 	g_signal_connect (edata->new_archive,
8045 			  "working-archive",
8046 			  G_CALLBACK (fr_window_working_archive_cb),
8047 			  window);
8048 
8049 	_archive_operation_started (window, FR_ACTION_ENCRYPTING_ARCHIVE);
8050 	fr_window_set_current_action (window,
8051 					    FR_BATCH_ACTION_ENCRYPT,
8052 					    edata,
8053 					    (GFreeFunc) encrypt_data_free);
8054 
8055 	fr_archive_action_started (window->archive, FR_ACTION_EXTRACTING_FILES);
8056 	fr_archive_extract (window->archive,
8057 			    NULL,
8058 			    edata->temp_extraction_dir,
8059 			    NULL,
8060 			    FALSE,
8061 			    TRUE,
8062 			    FALSE,
8063 			    window->priv->password,
8064 			    window->priv->cancellable,
8065 			    archive_extraction_ready_for_encryption_cb,
8066 			    edata);
8067 }
8068 
8069 
8070 /* -- fr_window_view_last_output  -- */
8071 
8072 
8073 static gboolean
last_output_window__unrealize_cb(GtkWidget * widget,gpointer data)8074 last_output_window__unrealize_cb (GtkWidget  *widget,
8075 				  gpointer    data)
8076 {
8077 	pref_util_save_window_geometry (GTK_WINDOW (widget), LAST_OUTPUT_SCHEMA_NAME);
8078 	return FALSE;
8079 }
8080 
8081 
8082 void
fr_window_view_last_output(FrWindow * window,const char * title)8083 fr_window_view_last_output (FrWindow   *window,
8084 			    const char *title)
8085 {
8086 	GtkWidget     *dialog;
8087 	GtkWidget     *vbox;
8088 	GtkWidget     *text_view;
8089 	GtkWidget     *scrolled;
8090 	GtkTextBuffer *text_buffer;
8091 	GtkTextIter    iter;
8092 	GList         *scan;
8093 
8094 	if (title == NULL)
8095 		title = _("Last Output");
8096 
8097 	dialog = g_object_new (GTK_TYPE_DIALOG,
8098 			       "title", title,
8099 			       "transient-for", window,
8100 			       "destroy-with-parent", TRUE,
8101 			       "use-header-bar", TRUE,
8102 			       NULL);
8103 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
8104 	gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
8105 	gtk_widget_set_size_request (dialog, 500, 300);
8106 
8107 	/* Add text */
8108 
8109 	scrolled = gtk_scrolled_window_new (NULL, NULL);
8110 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
8111 					GTK_POLICY_AUTOMATIC,
8112 					GTK_POLICY_AUTOMATIC);
8113 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
8114 					     GTK_SHADOW_ETCHED_IN);
8115 
8116 	text_buffer = gtk_text_buffer_new (NULL);
8117 	gtk_text_buffer_create_tag (text_buffer, "monospace",
8118 				    "family", "monospace", NULL);
8119 
8120 	text_view = gtk_text_view_new_with_buffer (text_buffer);
8121 	g_object_unref (text_buffer);
8122 	gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
8123 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE);
8124 
8125 	/**/
8126 
8127 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
8128 	gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
8129 
8130 	gtk_container_add (GTK_CONTAINER (scrolled), text_view);
8131 	gtk_box_pack_start (GTK_BOX (vbox), scrolled,
8132 			    TRUE, TRUE, 0);
8133 
8134 	gtk_widget_show_all (vbox);
8135 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
8136 			    vbox,
8137 			    TRUE, TRUE, 0);
8138 
8139 	/* signals */
8140 
8141 	g_signal_connect (G_OBJECT (dialog),
8142 			  "response",
8143 			  G_CALLBACK (gtk_widget_destroy),
8144 			  NULL);
8145 
8146 	g_signal_connect (G_OBJECT (dialog),
8147 			  "unrealize",
8148 			  G_CALLBACK (last_output_window__unrealize_cb),
8149 			  NULL);
8150 
8151 	/**/
8152 
8153 	gtk_text_buffer_get_iter_at_offset (text_buffer, &iter, 0);
8154 	if (FR_IS_COMMAND (window->archive))
8155 		scan = fr_command_get_last_output (FR_COMMAND (window->archive));
8156 	else
8157 		scan = NULL;
8158 	for (; scan; scan = scan->next) {
8159 		char        *line = scan->data;
8160 		char        *utf8_line;
8161 		gsize        bytes_written;
8162 
8163 		utf8_line = g_locale_to_utf8 (line, -1, NULL, &bytes_written, NULL);
8164 		gtk_text_buffer_insert_with_tags_by_name (text_buffer,
8165 							  &iter,
8166 							  utf8_line,
8167 							  bytes_written,
8168 							  "monospace", NULL);
8169 		g_free (utf8_line);
8170 		gtk_text_buffer_insert (text_buffer, &iter, "\n", 1);
8171 	}
8172 
8173 	/**/
8174 
8175 	pref_util_restore_window_geometry (GTK_WINDOW (dialog), LAST_OUTPUT_SCHEMA_NAME);
8176 }
8177 
8178 
8179 /* -- fr_window_rename_selection -- */
8180 
8181 
8182 typedef struct {
8183 	char     *path_to_rename;
8184 	char     *old_name;
8185 	char     *new_name;
8186 	char     *current_dir;
8187 	gboolean  is_dir;
8188 	gboolean  dir_in_archive;
8189 	char     *original_path;
8190 } RenameData;
8191 
8192 
8193 static RenameData*
rename_data_new(const char * path_to_rename,const char * old_name,const char * new_name,const char * current_dir,gboolean is_dir,gboolean dir_in_archive,const char * original_path)8194 rename_data_new (const char *path_to_rename,
8195 		 const char *old_name,
8196 		 const char *new_name,
8197 		 const char *current_dir,
8198 		 gboolean    is_dir,
8199 		 gboolean    dir_in_archive,
8200 		 const char *original_path)
8201 {
8202 	RenameData *rdata;
8203 
8204 	rdata = g_new0 (RenameData, 1);
8205 	rdata->path_to_rename = g_strdup (path_to_rename);
8206 	if (old_name != NULL)
8207 		rdata->old_name = g_strdup (old_name);
8208 	if (new_name != NULL)
8209 		rdata->new_name = g_strdup (new_name);
8210 	if (current_dir != NULL)
8211 		rdata->current_dir = g_strdup (current_dir);
8212 	rdata->is_dir = is_dir;
8213 	rdata->dir_in_archive = dir_in_archive;
8214 	if (original_path != NULL)
8215 		rdata->original_path = g_strdup (original_path);
8216 
8217 	return rdata;
8218 }
8219 
8220 
8221 static void
rename_data_free(RenameData * rdata)8222 rename_data_free (RenameData *rdata)
8223 {
8224 	g_return_if_fail (rdata != NULL);
8225 
8226 	g_free (rdata->path_to_rename);
8227 	g_free (rdata->old_name);
8228 	g_free (rdata->new_name);
8229 	g_free (rdata->current_dir);
8230 	g_free (rdata->original_path);
8231 	g_free (rdata);
8232 }
8233 
8234 
8235 static void
archive_rename_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8236 archive_rename_ready_cb (GObject      *source_object,
8237 			 GAsyncResult *result,
8238 			 gpointer      user_data)
8239 {
8240 	FrWindow *window = user_data;
8241 	GError   *error = NULL;
8242 
8243 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
8244 	_archive_operation_completed (window, FR_ACTION_RENAMING_FILES, error);
8245 
8246 	_g_error_free (error);
8247 }
8248 
8249 
8250 static void
rename_selection(FrWindow * window,const char * path_to_rename,const char * old_name,const char * new_name,const char * current_dir,gboolean is_dir,gboolean dir_in_archive,const char * original_path)8251 rename_selection (FrWindow   *window,
8252 		  const char *path_to_rename,
8253 		  const char *old_name,
8254 		  const char *new_name,
8255 		  const char *current_dir,
8256 		  gboolean    is_dir,
8257 		  gboolean    dir_in_archive,
8258 		  const char *original_path)
8259 {
8260 	RenameData *rdata;
8261 	GList      *file_list;
8262 
8263 	rdata = rename_data_new (path_to_rename,
8264 				 old_name,
8265 				 new_name,
8266 				 current_dir,
8267 				 is_dir,
8268 				 dir_in_archive,
8269 				 original_path);
8270 	fr_window_set_current_action (window,
8271 					    FR_BATCH_ACTION_RENAME,
8272 					    rdata,
8273 					    (GFreeFunc) rename_data_free);
8274 
8275 	_archive_operation_started (window, FR_ACTION_RENAMING_FILES);
8276 
8277 	g_object_set (window->archive,
8278 		      "compression", window->priv->compression,
8279 		      "encrypt-header", window->priv->encrypt_header,
8280 		      "password", window->priv->password,
8281 		      "volume-size", window->priv->volume_size,
8282 		      NULL);
8283 
8284 	if (is_dir)
8285 		file_list = get_dir_list_from_path (window, rdata->path_to_rename);
8286 	else
8287 		file_list = g_list_append (NULL, g_strdup (rdata->path_to_rename));
8288 	fr_window_clipboard_remove_file_list (window, file_list);
8289 	fr_archive_rename (window->archive,
8290 			   file_list,
8291 			   rdata->old_name,
8292 			   rdata->new_name,
8293 			   rdata->current_dir,
8294 			   rdata->is_dir,
8295 			   rdata->dir_in_archive,
8296 			   rdata->original_path,
8297 			   window->priv->cancellable,
8298 			   archive_rename_ready_cb,
8299 			   window);
8300 
8301 	_g_string_list_free (file_list);
8302 }
8303 
8304 
8305 static gboolean
valid_name(const char * new_name,const char * old_name,char ** reason)8306 valid_name (const char  *new_name,
8307 	    const char  *old_name,
8308 	    char       **reason)
8309 {
8310 	char     *utf8_new_name;
8311 	gboolean  retval = TRUE;
8312 
8313 	new_name = _g_str_eat_spaces (new_name);
8314 	utf8_new_name = g_filename_display_name (new_name);
8315 
8316 	if (*new_name == '\0') {
8317 		/* Translators: the name references to a filename.  This message can appear when renaming a file. */
8318 		*reason = g_strdup (_("New name is void, please type a name."));
8319 		retval = FALSE;
8320 	}
8321 	else if (strcmp (new_name, old_name) == 0) {
8322 		/* Translators: the name references to a filename.  This message can appear when renaming a file. */
8323 		*reason = g_strdup (_("New name is the same as old one, please type other name."));
8324 		retval = FALSE;
8325 	}
8326 	else if (_g_strchrs (new_name, BAD_CHARS)) {
8327 		/* Translators: the %s references to a filename.  This message can appear when renaming a file. */
8328 		*reason = g_strdup_printf (_("Name “%s” is not valid because it contains at least one of the following characters: %s, please type other name."), utf8_new_name, BAD_CHARS);
8329 		retval = FALSE;
8330 	}
8331 
8332 	g_free (utf8_new_name);
8333 
8334 	return retval;
8335 }
8336 
8337 
8338 static gboolean
name_is_present(FrWindow * window,const char * current_dir,const char * new_name,char ** reason)8339 name_is_present (FrWindow    *window,
8340 		 const char  *current_dir,
8341 		 const char  *new_name,
8342 		 char       **reason)
8343 {
8344 	gboolean  retval = FALSE;
8345 	int       i;
8346 	char     *new_filename;
8347 	int       new_filename_l;
8348 
8349 	*reason = NULL;
8350 
8351 	new_filename = g_build_filename (current_dir, new_name, NULL);
8352 	new_filename_l = strlen (new_filename);
8353 
8354 	for (i = 0; i < window->archive->files->len; i++) {
8355 		FileData   *fdata = g_ptr_array_index (window->archive->files, i);
8356 		const char *filename = fdata->full_path;
8357 
8358 		if ((strncmp (filename, new_filename, new_filename_l) == 0)
8359 		    && ((filename[new_filename_l] == '\0')
8360 			|| (filename[new_filename_l] == G_DIR_SEPARATOR))) {
8361 			char *utf8_name = g_filename_display_name (new_name);
8362 
8363 			if (filename[new_filename_l] == G_DIR_SEPARATOR)
8364 				*reason = g_strdup_printf (_("A folder named “%s” already exists.\n\n%s"), utf8_name, _("Please use a different name."));
8365 			else
8366 				*reason = g_strdup_printf (_("A file named “%s” already exists.\n\n%s"), utf8_name, _("Please use a different name."));
8367 
8368 			retval = TRUE;
8369 			break;
8370 		}
8371 	}
8372 
8373 	g_free (new_filename);
8374 
8375 	return retval;
8376 }
8377 
8378 
8379 void
fr_window_rename_selection(FrWindow * window,gboolean from_sidebar)8380 fr_window_rename_selection (FrWindow *window,
8381 			    gboolean  from_sidebar)
8382 {
8383 	char     *path_to_rename;
8384 	char     *parent_dir;
8385 	char     *old_name;
8386 	gboolean  renaming_dir = FALSE;
8387 	gboolean  dir_in_archive = FALSE;
8388 	char     *original_path = NULL;
8389 	char     *utf8_old_name;
8390 	char     *utf8_new_name;
8391 
8392 	if (from_sidebar) {
8393 		path_to_rename = fr_window_get_selected_folder_in_tree_view (window);
8394 		if (path_to_rename == NULL)
8395 			return;
8396 		parent_dir = _g_path_remove_level (path_to_rename);
8397 		old_name = g_strdup (_g_path_get_basename (path_to_rename));
8398 		renaming_dir = TRUE;
8399 	}
8400 	else {
8401 		FileData *selected_item;
8402 
8403 		selected_item = fr_window_get_selected_item_from_file_list (window);
8404 		if (selected_item == NULL)
8405 			return;
8406 
8407 		renaming_dir = file_data_is_dir (selected_item);
8408 		dir_in_archive = selected_item->dir && ! selected_item->list_dir;
8409 		original_path = g_strdup (selected_item->original_path);
8410 
8411 		if (renaming_dir && ! dir_in_archive) {
8412 			parent_dir = g_strdup (fr_window_get_current_location (window));
8413 			old_name = g_strdup (selected_item->list_name);
8414 			path_to_rename = g_build_filename (parent_dir, old_name, NULL);
8415 		}
8416 		else {
8417 			if (renaming_dir) {
8418 				path_to_rename = _g_path_remove_ending_separator (selected_item->full_path);
8419 				parent_dir = _g_path_remove_level (path_to_rename);
8420 			}
8421 			else {
8422 				path_to_rename = g_strdup (selected_item->original_path);
8423 				parent_dir = _g_path_remove_level (selected_item->full_path);
8424 			}
8425 			old_name = g_strdup (selected_item->name);
8426 		}
8427 
8428 		file_data_free (selected_item);
8429 	}
8430 
8431  retry__rename_selection:
8432 	utf8_old_name = g_locale_to_utf8 (old_name, -1 ,0 ,0 ,0);
8433 	utf8_new_name = _gtk_request_dialog_run (GTK_WINDOW (window),
8434 						 (GTK_DIALOG_DESTROY_WITH_PARENT
8435 						  | GTK_DIALOG_MODAL),
8436 						 _("Rename"),
8437 						 (renaming_dir ? _("_New folder name:") : _("_New file name:")),
8438 						 utf8_old_name,
8439 						 1024,
8440 						 _GTK_LABEL_CANCEL,
8441 						 _("_Rename"));
8442 	g_free (utf8_old_name);
8443 
8444 	if (utf8_new_name != NULL) {
8445 		char *new_name;
8446 		char *reason = NULL;
8447 
8448 		new_name = g_filename_from_utf8 (utf8_new_name, -1, 0, 0, 0);
8449 		g_free (utf8_new_name);
8450 
8451 		if (! valid_name (new_name, old_name, &reason)) {
8452 			char      *utf8_name = g_filename_display_name (new_name);
8453 			GtkWidget *dlg;
8454 
8455 			dlg = _gtk_error_dialog_new (GTK_WINDOW (window),
8456 						     GTK_DIALOG_DESTROY_WITH_PARENT,
8457 						     NULL,
8458 						     (renaming_dir ? _("Could not rename the folder") : _("Could not rename the file")),
8459 						     "%s",
8460 						     reason);
8461 			gtk_dialog_run (GTK_DIALOG (dlg));
8462 			gtk_widget_destroy (dlg);
8463 
8464 			g_free (reason);
8465 			g_free (utf8_name);
8466 			g_free (new_name);
8467 
8468 			goto retry__rename_selection;
8469 		}
8470 
8471 		if (name_is_present (window, parent_dir, new_name, &reason)) {
8472 			GtkWidget *dlg;
8473 
8474 			dlg = _gtk_message_dialog_new (GTK_WINDOW (window),
8475 						       GTK_DIALOG_MODAL,
8476 						       (renaming_dir ? _("Could not rename the folder") : _("Could not rename the file")),
8477 						       reason,
8478 						       _GTK_LABEL_CLOSE, GTK_RESPONSE_OK,
8479 						       NULL);
8480 			gtk_dialog_run (GTK_DIALOG (dlg));
8481 			gtk_widget_destroy (dlg);
8482 			g_free (reason);
8483 			g_free (new_name);
8484 			goto retry__rename_selection;
8485 		}
8486 
8487 		rename_selection (window,
8488 				  path_to_rename,
8489 				  old_name,
8490 				  new_name,
8491 				  parent_dir,
8492 				  renaming_dir,
8493 				  dir_in_archive,
8494 				  original_path);
8495 
8496 		g_free (new_name);
8497 	}
8498 
8499 	g_free (old_name);
8500 	g_free (parent_dir);
8501 	g_free (path_to_rename);
8502 	g_free (original_path);
8503 }
8504 
8505 
8506 /* -- fr_window_paste_selection -- */
8507 
8508 
8509 static void
fr_clipboard_get(GtkClipboard * clipboard,GtkSelectionData * selection_data,guint info,gpointer user_data_or_owner)8510 fr_clipboard_get (GtkClipboard     *clipboard,
8511 		  GtkSelectionData *selection_data,
8512 		  guint             info,
8513 		  gpointer          user_data_or_owner)
8514 {
8515 	FrWindow *window = user_data_or_owner;
8516 	char     *data;
8517 
8518 	if (gtk_selection_data_get_target (selection_data) != FR_SPECIAL_URI_LIST)
8519 		return;
8520 
8521 	data = get_selection_data_from_clipboard_data (window, window->priv->copy_data);
8522 	if (data != NULL) {
8523 		gtk_selection_data_set (selection_data,
8524 					gtk_selection_data_get_target (selection_data),
8525 					8,
8526 					(guchar *) data,
8527 					strlen (data));
8528 		g_free (data);
8529 	}
8530 }
8531 
8532 
8533 static void
fr_clipboard_clear(GtkClipboard * clipboard,gpointer user_data_or_owner)8534 fr_clipboard_clear (GtkClipboard *clipboard,
8535 		    gpointer      user_data_or_owner)
8536 {
8537 	FrWindow *window = user_data_or_owner;
8538 
8539 	if (window->priv->copy_data != NULL) {
8540 		fr_clipboard_data_unref (window->priv->copy_data);
8541 		window->priv->copy_data = NULL;
8542 	}
8543 }
8544 
8545 
8546 GList *
fr_window_get_selection(FrWindow * window,gboolean from_sidebar,char ** return_base_dir)8547 fr_window_get_selection (FrWindow   *window,
8548 		  	 gboolean    from_sidebar,
8549 		  	 char      **return_base_dir)
8550 {
8551 	GList *files;
8552 	char  *base_dir;
8553 
8554 	if (from_sidebar) {
8555 		char *selected_folder;
8556 		char *parent_folder;
8557 
8558 		files = fr_window_get_folder_tree_selection (window, TRUE, NULL);
8559 		selected_folder = fr_window_get_selected_folder_in_tree_view (window);
8560 		parent_folder = _g_path_remove_level (selected_folder);
8561 		if (parent_folder == NULL)
8562 			base_dir = g_strdup ("/");
8563 		else if (parent_folder[strlen (parent_folder) - 1] == '/')
8564 			base_dir = g_strdup (parent_folder);
8565 		else
8566 			base_dir = g_strconcat (parent_folder, "/", NULL);
8567 		g_free (selected_folder);
8568 		g_free (parent_folder);
8569 	}
8570 	else {
8571 		files = fr_window_get_file_list_selection (window, TRUE, NULL);
8572 		base_dir = g_strdup (fr_window_get_current_location (window));
8573 	}
8574 
8575 	if (return_base_dir)
8576 		*return_base_dir = base_dir;
8577 	else
8578 		g_free (base_dir);
8579 
8580 	return files;
8581 }
8582 
8583 
8584 static void
fr_window_copy_or_cut_selection(FrWindow * window,FrClipboardOp op,gboolean from_sidebar)8585 fr_window_copy_or_cut_selection (FrWindow      *window,
8586 				 FrClipboardOp  op,
8587 			  	 gboolean       from_sidebar)
8588 {
8589 	GList        *files;
8590 	char         *base_dir;
8591 	GtkClipboard *clipboard;
8592 
8593 	files = fr_window_get_selection (window, from_sidebar, &base_dir);
8594 
8595 	if (window->priv->copy_data != NULL)
8596 		fr_clipboard_data_unref (window->priv->copy_data);
8597 	window->priv->copy_data = fr_clipboard_data_new ();
8598 	window->priv->copy_data->files = files;
8599 	window->priv->copy_data->op = op;
8600 	window->priv->copy_data->base_dir = base_dir;
8601 
8602 	clipboard = gtk_clipboard_get (_fr_window_get_clipboard_name (window));
8603 	gtk_clipboard_set_with_owner (clipboard,
8604 				      clipboard_targets,
8605 				      G_N_ELEMENTS (clipboard_targets),
8606 				      fr_clipboard_get,
8607 				      fr_clipboard_clear,
8608 				      G_OBJECT (window));
8609 
8610 	fr_window_update_sensitivity (window);
8611 }
8612 
8613 
8614 void
fr_window_copy_selection(FrWindow * window,gboolean from_sidebar)8615 fr_window_copy_selection (FrWindow *window,
8616 			  gboolean  from_sidebar)
8617 {
8618 	fr_window_copy_or_cut_selection (window, FR_CLIPBOARD_OP_COPY, from_sidebar);
8619 }
8620 
8621 
8622 void
fr_window_cut_selection(FrWindow * window,gboolean from_sidebar)8623 fr_window_cut_selection (FrWindow *window,
8624 			 gboolean  from_sidebar)
8625 {
8626 	fr_window_copy_or_cut_selection (window, FR_CLIPBOARD_OP_CUT, from_sidebar);
8627 }
8628 
8629 
8630 /* -- fr_window_paste_from_clipboard_data -- */
8631 
8632 
8633 static void
_paste_from_archive_operation_completed(FrWindow * window,FrAction action,GError * error)8634 _paste_from_archive_operation_completed (FrWindow *window,
8635 					 FrAction  action,
8636 					 GError   *error)
8637 {
8638 	FrArchive *archive;
8639 
8640 #ifdef DEBUG
8641 	debug (DEBUG_INFO, "%s [DONE] (FR::Window)\n", action_names[action]);
8642 #endif
8643 
8644 	_fr_window_stop_activity_mode (window);
8645 	close_progress_dialog (window, FALSE);
8646 
8647 	if ((error != NULL) && (error->code == FR_ERROR_ASK_PASSWORD)) {
8648 		dlg_ask_password_for_second_archive (window);
8649 		return;
8650 	}
8651 
8652 	if (action == FR_ACTION_ADDING_FILES)
8653 		archive = window->archive;
8654 	else
8655 		archive = window->priv->copy_from_archive;
8656 	_handle_archive_operation_error (window, archive, action, error, NULL, NULL);
8657 
8658 	if (error != NULL) {
8659 		if (window->priv->second_password != NULL) {
8660 			g_free (window->priv->second_password);
8661 			window->priv->second_password = NULL;
8662 		}
8663 
8664 		fr_clipboard_data_unref (window->priv->clipboard_data);
8665 		window->priv->clipboard_data = NULL;
8666 	}
8667 }
8668 
8669 
8670 static void
paste_from_archive_completed_successfully(FrWindow * window)8671 paste_from_archive_completed_successfully (FrWindow *window)
8672 {
8673 	_paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, NULL);
8674 
8675 	fr_clipboard_data_unref (window->priv->clipboard_data);
8676 	window->priv->clipboard_data = NULL;
8677 
8678 	if (window->priv->second_password != NULL) {
8679 		g_free (window->priv->second_password);
8680 		window->priv->second_password = NULL;
8681 	}
8682 
8683 	window->priv->archive_new = FALSE;
8684 	fr_window_archive_reload (window);
8685 }
8686 
8687 
8688 static void
paste_from_archive_remove_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8689 paste_from_archive_remove_ready_cb (GObject      *source_object,
8690 				    GAsyncResult *result,
8691 				    gpointer      user_data)
8692 {
8693 	FrWindow *window = user_data;
8694 	GError   *error = NULL;
8695 
8696 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8697 		_paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8698 		g_error_free (error);
8699 		return;
8700 	}
8701 
8702 	paste_from_archive_completed_successfully (window);
8703 }
8704 
8705 
8706 static void
paste_from_archive_paste_clipboard_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8707 paste_from_archive_paste_clipboard_ready_cb (GObject      *source_object,
8708 					     GAsyncResult *result,
8709 					     gpointer      user_data)
8710 {
8711 	FrWindow *window = user_data;
8712 	GError   *error = NULL;
8713 
8714 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8715 		_paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8716 		g_error_free (error);
8717 		return;
8718 	}
8719 
8720 	if (window->priv->clipboard_data->op == FR_CLIPBOARD_OP_CUT) {
8721 		fr_archive_action_started (window->priv->copy_from_archive, FR_ACTION_DELETING_FILES);
8722 		fr_archive_remove (window->priv->copy_from_archive,
8723 				   window->priv->clipboard_data->files,
8724 				   window->priv->compression,
8725 				   window->priv->cancellable,
8726 				   paste_from_archive_remove_ready_cb,
8727 				   window);
8728 	}
8729 	else
8730 		paste_from_archive_completed_successfully (window);
8731 }
8732 
8733 
8734 static void
paste_from_archive_extract_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8735 paste_from_archive_extract_ready_cb (GObject      *source_object,
8736 				     GAsyncResult *result,
8737 				     gpointer      user_data)
8738 {
8739 	FrWindow *window = user_data;
8740 	GError   *error = NULL;
8741 
8742 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8743 		_paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8744 		g_error_free (error);
8745 		return;
8746 	}
8747 
8748 	fr_archive_paste_clipboard (window->archive,
8749 				    window->priv->clipboard_data->file,
8750 				    window->priv->password,
8751 				    window->priv->encrypt_header,
8752 				    window->priv->compression,
8753 				    window->priv->volume_size,
8754 				    window->priv->clipboard_data->op,
8755 				    window->priv->clipboard_data->base_dir,
8756 				    window->priv->clipboard_data->files,
8757 				    window->priv->clipboard_data->tmp_dir,
8758 				    window->priv->clipboard_data->current_dir,
8759 				    window->priv->cancellable,
8760 				    paste_from_archive_paste_clipboard_ready_cb,
8761 				    window);
8762 }
8763 
8764 
8765 static void
paste_from_archive_list_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8766 paste_from_archive_list_ready_cb (GObject      *source_object,
8767 				  GAsyncResult *result,
8768 				  gpointer      user_data)
8769 {
8770 	FrWindow *window = user_data;
8771 	GError   *error = NULL;
8772 
8773 	if (! fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error)) {
8774 		_paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8775 		g_error_free (error);
8776 		return;
8777 	}
8778 
8779 	fr_archive_action_started (window->priv->copy_from_archive, FR_ACTION_EXTRACTING_FILES);
8780 	fr_archive_extract (window->priv->copy_from_archive,
8781 			    window->priv->clipboard_data->files,
8782 			    window->priv->clipboard_data->tmp_dir,
8783 			    NULL,
8784 			    FALSE,
8785 			    TRUE,
8786 			    FALSE,
8787 			    window->priv->clipboard_data->password,
8788 			    window->priv->cancellable,
8789 			    paste_from_archive_extract_ready_cb,
8790 			    window);
8791 }
8792 
8793 
8794 static void
paste_from_archive_open_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)8795 paste_from_archive_open_cb (GObject      *source_object,
8796 			    GAsyncResult *result,
8797 			    gpointer      user_data)
8798 {
8799 	FrWindow *window = user_data;
8800 	GError   *error;
8801 
8802 	_g_object_unref (window->priv->copy_from_archive);
8803 	window->priv->copy_from_archive = fr_archive_open_finish (G_FILE (source_object), result, &error);
8804 	if (window->priv->copy_from_archive == NULL) {
8805 		_paste_from_archive_operation_completed (window, FR_ACTION_PASTING_FILES, error);
8806 		g_error_free (error);
8807 		return;
8808 	}
8809 
8810 	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8811 			  "progress",
8812 			  G_CALLBACK (fr_archive_progress_cb),
8813 			  window);
8814 	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8815 			  "message",
8816 			  G_CALLBACK (fr_archive_message_cb),
8817 			  window);
8818 	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8819 			  "start",
8820 			  G_CALLBACK (fr_archive_start_cb),
8821 			  window);
8822 	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8823 			  "stoppable",
8824 			  G_CALLBACK (fr_archive_stoppable_cb),
8825 			  window);
8826 	g_signal_connect (G_OBJECT (window->priv->copy_from_archive),
8827 			  "working-archive",
8828 			  G_CALLBACK (fr_window_working_archive_cb),
8829 			  window);
8830 
8831 	fr_archive_action_started (window->priv->copy_from_archive, FR_ACTION_LISTING_CONTENT);
8832 	fr_archive_list (window->priv->copy_from_archive,
8833 			 window->priv->clipboard_data->password,
8834 			 window->priv->cancellable,
8835 			 paste_from_archive_list_ready_cb,
8836 			 window);
8837 }
8838 
8839 
8840 static void
_window_started_loading_file(FrWindow * window,GFile * file)8841 _window_started_loading_file (FrWindow *window,
8842 			      GFile    *file)
8843 {
8844 	char *description;
8845 
8846 	description = get_action_description (window, FR_ACTION_LOADING_ARCHIVE, file);
8847 	fr_archive_message_cb (NULL, description, window);
8848 
8849 	g_free (description);
8850 }
8851 
8852 
8853 static void
fr_window_paste_from_clipboard_data(FrWindow * window,FrClipboardData * data)8854 fr_window_paste_from_clipboard_data (FrWindow        *window,
8855 				     FrClipboardData *data)
8856 {
8857 	const char *current_dir_relative;
8858 	GHashTable *created_dirs;
8859 	GList      *scan;
8860 	char       *from_archive;
8861 	char       *to_archive;
8862 
8863 	if (window->priv->second_password != NULL)
8864 		fr_clipboard_data_set_password (data, window->priv->second_password);
8865 
8866 	if (window->priv->clipboard_data != data) {
8867 		fr_clipboard_data_unref (window->priv->clipboard_data);
8868 		window->priv->clipboard_data = data;
8869 	}
8870 
8871 	fr_window_set_current_action (window,
8872 					    FR_BATCH_ACTION_PASTE,
8873 					    fr_clipboard_data_ref (data),
8874 					    (GFreeFunc) fr_clipboard_data_unref);
8875 
8876 	current_dir_relative = data->current_dir + 1;
8877 
8878 	data->tmp_dir = _g_file_get_temp_work_dir (NULL);
8879 	created_dirs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
8880 	for (scan = data->files; scan; scan = scan->next) {
8881 		const char *old_name = (char*) scan->data;
8882 		char       *new_name;
8883 		char       *dir;
8884 
8885 		new_name = g_build_filename (current_dir_relative, old_name + strlen (data->base_dir) - 1, NULL);
8886 		dir = _g_path_remove_level (new_name);
8887 		if ((dir != NULL) && (g_hash_table_lookup (created_dirs, dir) == NULL)) {
8888 			GFile *directory;
8889 			char *uri;
8890 
8891 			directory = _g_file_append_path (data->tmp_dir, dir, NULL);
8892 			uri = g_file_get_uri (directory);
8893 			debug (DEBUG_INFO, "mktree %s\n", uri);
8894 			_g_file_make_directory_tree (directory, 0700, NULL);
8895 
8896 			g_hash_table_replace (created_dirs, g_strdup (dir), GINT_TO_POINTER (1));
8897 
8898 			g_object_unref (directory);
8899 			g_free (uri);
8900 		}
8901 
8902 		g_free (dir);
8903 		g_free (new_name);
8904 	}
8905 	g_hash_table_destroy (created_dirs);
8906 
8907 	/**/
8908 
8909 	g_free (window->priv->custom_action_message);
8910 	from_archive = _g_file_get_display_basename (data->file);
8911 	to_archive = _g_file_get_display_basename (window->priv->archive_file);
8912 	if (data->op == FR_CLIPBOARD_OP_CUT)
8913 		/* Translators: %s are archive filenames */
8914 		window->priv->custom_action_message = g_strdup_printf (_("Moving the files from “%s” to “%s”"), from_archive, to_archive);
8915 	else
8916 		/* Translators: %s are archive filenames */
8917 		window->priv->custom_action_message = g_strdup_printf (_("Copying the files from “%s” to “%s”"), from_archive, to_archive);
8918 	_archive_operation_started (window, FR_ACTION_PASTING_FILES);
8919 
8920 	_window_started_loading_file (window, data->file);
8921 	fr_archive_open (data->file,
8922 			 window->priv->cancellable,
8923 			 paste_from_archive_open_cb,
8924 			 window);
8925 
8926 	g_free (to_archive);
8927 	g_free (from_archive);
8928 }
8929 
8930 
8931 static void
fr_window_paste_selection_to(FrWindow * window,const char * current_dir)8932 fr_window_paste_selection_to (FrWindow   *window,
8933 			      const char *current_dir)
8934 {
8935 	GtkClipboard     *clipboard;
8936 	GtkSelectionData *selection_data;
8937 	FrClipboardData  *paste_data;
8938 
8939 	clipboard = gtk_clipboard_get (_fr_window_get_clipboard_name (window));
8940 	selection_data = gtk_clipboard_wait_for_contents (clipboard, FR_SPECIAL_URI_LIST);
8941 	if (selection_data == NULL)
8942 		return;
8943 
8944 	paste_data = get_clipboard_data_from_selection_data (window, (char*) gtk_selection_data_get_data (selection_data));
8945 	paste_data->current_dir = g_strdup (current_dir);
8946 	fr_window_paste_from_clipboard_data (window, paste_data);
8947 
8948 	gtk_selection_data_free (selection_data);
8949 }
8950 
8951 
8952 void
fr_window_paste_selection(FrWindow * window,gboolean from_sidebar)8953 fr_window_paste_selection (FrWindow *window,
8954 			   gboolean  from_sidebar)
8955 {
8956 	char *utf8_path, *utf8_old_path, *destination;
8957 	char *current_dir;
8958 
8959 	if (window->priv->list_mode == FR_WINDOW_LIST_MODE_FLAT)
8960 		return;
8961 
8962 	/**/
8963 
8964 	utf8_old_path = g_filename_to_utf8 (fr_window_get_current_location (window), -1, NULL, NULL, NULL);
8965 	utf8_path = _gtk_request_dialog_run (GTK_WINDOW (window),
8966 					       (GTK_DIALOG_DESTROY_WITH_PARENT
8967 						| GTK_DIALOG_MODAL),
8968 					       _("Paste Selection"),
8969 					       _("_Destination folder:"),
8970 					       utf8_old_path,
8971 					       1024,
8972 					       _GTK_LABEL_CANCEL,
8973 					       _("_Paste"));
8974 	g_free (utf8_old_path);
8975 	if (utf8_path == NULL)
8976 		return;
8977 
8978 	destination = g_filename_from_utf8 (utf8_path, -1, NULL, NULL, NULL);
8979 	g_free (utf8_path);
8980 
8981 	if (destination[0] != '/')
8982 		current_dir = g_build_filename (fr_window_get_current_location (window), destination, NULL);
8983 	else
8984 		current_dir = g_strdup (destination);
8985 	g_free (destination);
8986 
8987 	fr_window_paste_selection_to (window, current_dir);
8988 
8989 	g_free (current_dir);
8990 }
8991 
8992 
8993 /* -- fr_window_open_files -- */
8994 
8995 
8996 void
fr_window_open_files_with_command(FrWindow * window,GList * file_list,char * command)8997 fr_window_open_files_with_command (FrWindow *window,
8998 				   GList    *file_list,
8999 				   char     *command)
9000 {
9001 	GAppInfo *app;
9002 	GError   *error = NULL;
9003 
9004 	app = g_app_info_create_from_commandline (command, NULL, G_APP_INFO_CREATE_NONE, &error);
9005 	if (error != NULL) {
9006 		_gtk_error_dialog_run (GTK_WINDOW (window),
9007 				       _("Could not perform the operation"),
9008 				       "%s",
9009 				       error->message);
9010 		g_clear_error (&error);
9011 		return;
9012 	}
9013 
9014 	fr_window_open_files_with_application (window, file_list, app);
9015 }
9016 
9017 
9018 void
fr_window_open_files_with_application(FrWindow * window,GList * file_list,GAppInfo * app)9019 fr_window_open_files_with_application (FrWindow *window,
9020 				       GList    *file_list,
9021 				       GAppInfo *app)
9022 {
9023 	GList               *uris;
9024 	GList               *scan;
9025 	GdkAppLaunchContext *context;
9026 	GError              *error = NULL;
9027 
9028 	if (window->priv->activity_ref > 0)
9029 		return;
9030 
9031 	uris = NULL;
9032 	for (scan = file_list; scan; scan = scan->next)
9033 		uris = g_list_prepend (uris, g_file_get_uri (G_FILE (scan->data)));
9034 
9035 	context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (window)));
9036 	gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (GTK_WIDGET (window)));
9037 	gdk_app_launch_context_set_timestamp (context, 0);
9038 
9039 	if (! g_app_info_launch_uris (app, uris, G_APP_LAUNCH_CONTEXT (context), &error)) {
9040 		_gtk_error_dialog_run (GTK_WINDOW (window),
9041 				       _("Could not perform the operation"),
9042 				       "%s",
9043 				       error->message);
9044 		g_clear_error (&error);
9045 	}
9046 
9047 	g_object_unref (context);
9048 	_g_string_list_free (uris);
9049 }
9050 
9051 
9052 typedef struct {
9053 	int          ref_count;
9054 	FrWindow    *window;
9055 	GList       *file_list;
9056 	gboolean     ask_application;
9057 	CommandData *cdata;
9058 } OpenFilesData;
9059 
9060 
9061 static OpenFilesData*
open_files_data_new(FrWindow * window,GList * file_list,gboolean ask_application)9062 open_files_data_new (FrWindow *window,
9063 		     GList    *file_list,
9064 		     gboolean  ask_application)
9065 
9066 {
9067 	OpenFilesData *odata;
9068 	GList         *scan;
9069 
9070 	odata = g_new0 (OpenFilesData, 1);
9071 	odata->ref_count = 1;
9072 	odata->window = g_object_ref (window);
9073 	odata->file_list = _g_string_list_dup (file_list);
9074 	odata->ask_application = ask_application;
9075 	odata->cdata = g_new0 (CommandData, 1);
9076 	odata->cdata->temp_dir = _g_file_get_temp_work_dir (NULL);
9077 	odata->cdata->file_list = NULL;
9078 	for (scan = file_list; scan; scan = scan->next) {
9079 		char  *filename = scan->data;
9080 		GFile *file;
9081 
9082 		file = _g_file_append_path (odata->cdata->temp_dir, filename, NULL);
9083 		odata->cdata->file_list = g_list_prepend (odata->cdata->file_list, file);
9084 	}
9085 
9086 	/* Add to CommandList so the cdata is released on exit. */
9087 	CommandList = g_list_prepend (CommandList, odata->cdata);
9088 
9089 	return odata;
9090 }
9091 
9092 
9093 static void
open_files_data_ref(OpenFilesData * odata)9094 open_files_data_ref (OpenFilesData *odata)
9095 {
9096 	g_return_if_fail (odata != NULL);
9097 	odata->ref_count++;
9098 }
9099 
9100 
9101 static void
open_files_data_unref(OpenFilesData * odata)9102 open_files_data_unref (OpenFilesData *odata)
9103 {
9104 	g_return_if_fail (odata != NULL);
9105 
9106 	if (--odata->ref_count > 0)
9107 		return;
9108 
9109 	_g_string_list_free (odata->file_list);
9110 	g_object_unref (odata->window);
9111 	g_free (odata);
9112 }
9113 
9114 
9115 /* -- -- */
9116 
9117 
9118 void
fr_window_update_dialog_closed(FrWindow * window)9119 fr_window_update_dialog_closed (FrWindow *window)
9120 {
9121 	window->priv->update_dialog = NULL;
9122 }
9123 
9124 
9125 static void
update_files_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)9126 update_files_ready_cb (GObject      *source_object,
9127 		       GAsyncResult *result,
9128 		       gpointer      user_data)
9129 {
9130 	FrWindow *window = user_data;
9131 	GError   *error = NULL;
9132 
9133 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
9134 	_archive_operation_completed (window, FR_ACTION_UPDATING_FILES, error);
9135 
9136 	_g_error_free (error);
9137 }
9138 
9139 
9140 gboolean
fr_window_update_files(FrWindow * window,GList * open_file_list)9141 fr_window_update_files (FrWindow *window,
9142 			GList    *open_file_list)
9143 {
9144 	GList *file_list;
9145 	GList *dir_list;
9146 	GList *scan;
9147 
9148 	if (window->priv->activity_ref > 0)
9149 		return FALSE;
9150 
9151 	if (window->archive->read_only)
9152 		return FALSE;
9153 
9154 	/* the size will be computed by the archive object */
9155 	window->archive->files_to_add_size = 0;
9156 
9157 	file_list = NULL;
9158 	dir_list = NULL;
9159 	for (scan = open_file_list; scan; scan = scan->next) {
9160 		OpenFile *open_file = scan->data;
9161 
9162 		file_list = g_list_prepend (file_list, g_object_ref (open_file->extracted_file));
9163 		dir_list = g_list_prepend (dir_list, g_object_ref (open_file->temp_dir));
9164 	}
9165 
9166 	_archive_operation_started (window, FR_ACTION_UPDATING_FILES);
9167 
9168 	fr_archive_update_open_files (window->archive,
9169 				      file_list,
9170 				      dir_list,
9171 				      window->priv->password,
9172 				      window->priv->encrypt_header,
9173 				      window->priv->compression,
9174 				      window->priv->volume_size,
9175 				      window->priv->cancellable,
9176 				      update_files_ready_cb,
9177 				      window);
9178 
9179 	_g_object_list_unref (dir_list);
9180 	_g_object_list_unref (file_list);
9181 
9182 	return TRUE;
9183 }
9184 
9185 
9186 static void
open_file_modified_cb(GFileMonitor * monitor,GFile * monitor_file,GFile * other_file,GFileMonitorEvent event_type,gpointer user_data)9187 open_file_modified_cb (GFileMonitor     *monitor,
9188 		       GFile            *monitor_file,
9189 		       GFile            *other_file,
9190 		       GFileMonitorEvent event_type,
9191 		       gpointer          user_data)
9192 {
9193 	FrWindow *window = user_data;
9194 	OpenFile *file;
9195 	GList    *scan;
9196 
9197 	if ((event_type != G_FILE_MONITOR_EVENT_CHANGED)
9198 	    && (event_type != G_FILE_MONITOR_EVENT_CREATED))
9199 	{
9200 		return;
9201 	}
9202 
9203 	file = NULL;
9204 	for (scan = window->priv->open_files; scan; scan = scan->next) {
9205 		OpenFile *test = scan->data;
9206 		if (_g_file_cmp_uris (test->extracted_file, monitor_file) == 0) {
9207 			file = test;
9208 			break;
9209 		}
9210 	}
9211 
9212 	g_return_if_fail (file != NULL);
9213 
9214 	if (window->priv->update_dialog == NULL)
9215 		window->priv->update_dialog = dlg_update (window);
9216 	dlg_update_add_file (window->priv->update_dialog, file);
9217 }
9218 
9219 
9220 static void
fr_window_monitor_open_file(FrWindow * window,OpenFile * file)9221 fr_window_monitor_open_file (FrWindow *window,
9222 			     OpenFile *file)
9223 {
9224 	window->priv->open_files = g_list_prepend (window->priv->open_files, file);
9225 	file->monitor = g_file_monitor_file (file->extracted_file, 0, NULL, NULL);
9226 	g_signal_connect (file->monitor,
9227 			  "changed",
9228 			  G_CALLBACK (open_file_modified_cb),
9229 			  window);
9230 }
9231 
9232 
9233 static void
monitor_extracted_files(OpenFilesData * odata)9234 monitor_extracted_files (OpenFilesData *odata)
9235 {
9236 	FrWindow *window = odata->window;
9237 	GList    *scan1, *scan2;
9238 
9239 	for (scan1 = odata->file_list, scan2 = odata->cdata->file_list;
9240 	     scan1 && scan2;
9241 	     scan1 = scan1->next, scan2 = scan2->next)
9242 	{
9243 		char     *original_path = (char *) scan1->data;
9244 		GFile    *extracted_file = G_FILE (scan2->data);
9245 		OpenFile *ofile;
9246 
9247 		ofile = open_file_new (original_path, extracted_file, odata->cdata->temp_dir);
9248 		if (ofile != NULL)
9249 			fr_window_monitor_open_file (window, ofile);
9250 	}
9251 }
9252 
9253 
9254 static gboolean
fr_window_open_extracted_files(OpenFilesData * odata)9255 fr_window_open_extracted_files (OpenFilesData *odata)
9256 {
9257 	GList               *file_list = odata->cdata->file_list;
9258 	GFile               *first_file;
9259 	const char          *first_mime_type;
9260 	GAppInfo            *app;
9261 	GList               *files_to_open = NULL;
9262 	GdkAppLaunchContext *context;
9263 	gboolean             result;
9264 	GError              *error = NULL;
9265 
9266 	g_return_val_if_fail (file_list != NULL, FALSE);
9267 
9268 	first_file = G_FILE (file_list->data);
9269 	if (first_file == NULL)
9270 		return FALSE;
9271 
9272 	if (! odata->window->archive->read_only)
9273 		monitor_extracted_files (odata);
9274 
9275 	if (odata->ask_application) {
9276 		dlg_open_with (odata->window, file_list);
9277 		return FALSE;
9278 	}
9279 
9280 	first_mime_type = _g_file_get_mime_type (first_file, FALSE);
9281 	app = g_app_info_get_default_for_type (first_mime_type, FALSE);
9282 
9283 	if (app == NULL) {
9284 		dlg_open_with (odata->window, file_list);
9285 		return FALSE;
9286 	}
9287 
9288 	files_to_open = g_list_append (files_to_open, g_file_get_uri (first_file));
9289 
9290 	if (g_app_info_supports_files (app)) {
9291 		GList *scan;
9292 
9293 		for (scan = file_list->next; scan; scan = scan->next) {
9294 			GFile      *file = G_FILE (scan->data);
9295 			const char *mime_type;
9296 
9297 			mime_type = _g_file_get_mime_type (file, FALSE);
9298 			if (mime_type == NULL)
9299 				continue;
9300 
9301 			if (strcmp (mime_type, first_mime_type) == 0) {
9302 				files_to_open = g_list_append (files_to_open, g_file_get_uri (file));
9303 			}
9304 			else {
9305 				GAppInfo *app2;
9306 
9307 				app2 = g_app_info_get_default_for_type (mime_type, FALSE);
9308 				if (g_app_info_equal (app, app2))
9309 					files_to_open = g_list_append (files_to_open, g_file_get_uri (file));
9310 				g_object_unref (app2);
9311 			}
9312 		}
9313 	}
9314 
9315 	context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (odata->window)));
9316 	gdk_app_launch_context_set_screen (context, gtk_widget_get_screen (GTK_WIDGET (odata->window)));
9317 	gdk_app_launch_context_set_timestamp (context, 0);
9318 	result = g_app_info_launch_uris (app, files_to_open, G_APP_LAUNCH_CONTEXT (context), &error);
9319 	if (! result) {
9320 		_gtk_error_dialog_run (GTK_WINDOW (odata->window),
9321 				       _("Could not perform the operation"),
9322 				       "%s",
9323 				       error->message);
9324 		g_clear_error (&error);
9325 	}
9326 
9327 	g_object_unref (context);
9328 	g_object_unref (app);
9329 	_g_string_list_free (files_to_open);
9330 
9331 	return result;
9332 }
9333 
9334 
9335 static void
open_files_extract_ready_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)9336 open_files_extract_ready_cb (GObject      *source_object,
9337 			     GAsyncResult *result,
9338 			     gpointer      user_data)
9339 {
9340 	OpenFilesData *odata = user_data;
9341 	GError        *error = NULL;
9342 
9343 	open_files_data_ref (odata);
9344 	fr_archive_operation_finish (FR_ARCHIVE (source_object), result, &error);
9345 	_archive_operation_completed (odata->window, FR_ACTION_EXTRACTING_FILES, error);
9346 
9347 	if (error == NULL)
9348 		fr_window_open_extracted_files (odata);
9349 
9350 	open_files_data_unref (odata);
9351 	_g_error_free (error);
9352 }
9353 
9354 
9355 void
fr_window_open_files(FrWindow * window,GList * file_list,gboolean ask_application)9356 fr_window_open_files (FrWindow *window,
9357 		      GList    *file_list,
9358 		      gboolean  ask_application)
9359 {
9360 	OpenFilesData *odata;
9361 
9362 	if (window->priv->activity_ref > 0)
9363 		return;
9364 
9365 	odata = open_files_data_new (window, file_list, ask_application);
9366 	fr_window_set_current_action (window,
9367 					    FR_BATCH_ACTION_OPEN_FILES,
9368 					    odata,
9369 					    (GFreeFunc) open_files_data_unref);
9370 
9371 	_archive_operation_started (odata->window, FR_ACTION_EXTRACTING_FILES);
9372 
9373 	fr_archive_extract (window->archive,
9374 			    odata->file_list,
9375 			    odata->cdata->temp_dir,
9376 			    NULL,
9377 			    FALSE,
9378 			    TRUE,
9379 			    FALSE,
9380 			    window->priv->password,
9381 			    window->priv->cancellable,
9382 			    open_files_extract_ready_cb,
9383 			    odata);
9384 }
9385 
9386 
9387 /**/
9388 
9389 
9390 static GFile *
_get_default_dir(GFile * directory)9391 _get_default_dir (GFile *directory)
9392 {
9393 	if (! _g_file_is_temp_dir (directory))
9394 		return g_object_ref (directory);
9395 	else
9396 		return NULL;
9397 }
9398 
9399 
9400 void
fr_window_set_open_default_dir(FrWindow * window,GFile * default_dir)9401 fr_window_set_open_default_dir (FrWindow *window,
9402 				GFile    *default_dir)
9403 {
9404 	g_return_if_fail (window != NULL);
9405 	g_return_if_fail (default_dir != NULL);
9406 
9407 	_g_object_unref (window->priv->open_default_dir);
9408 	window->priv->open_default_dir = _get_default_dir (default_dir);
9409 }
9410 
9411 
9412 GFile *
fr_window_get_open_default_dir(FrWindow * window)9413 fr_window_get_open_default_dir (FrWindow *window)
9414 {
9415 	if (window->priv->open_default_dir == NULL)
9416 		return _g_file_get_home ();
9417 	else
9418 		return  window->priv->open_default_dir;
9419 }
9420 
9421 
9422 void
fr_window_set_add_default_dir(FrWindow * window,GFile * default_dir)9423 fr_window_set_add_default_dir (FrWindow *window,
9424 			       GFile    *default_dir)
9425 {
9426 	g_return_if_fail (window != NULL);
9427 	g_return_if_fail (default_dir != NULL);
9428 
9429 	_g_object_unref (window->priv->add_default_dir);
9430 	window->priv->add_default_dir = _get_default_dir (default_dir);
9431 }
9432 
9433 
9434 GFile *
fr_window_get_add_default_dir(FrWindow * window)9435 fr_window_get_add_default_dir (FrWindow *window)
9436 {
9437 	return  window->priv->add_default_dir;
9438 }
9439 
9440 
9441 void
fr_window_set_extract_default_dir(FrWindow * window,GFile * default_dir)9442 fr_window_set_extract_default_dir (FrWindow *window,
9443 				   GFile    *default_dir)
9444 {
9445 	g_return_if_fail (window != NULL);
9446 	g_return_if_fail (default_dir != NULL);
9447 
9448 	_g_object_unref (window->priv->extract_default_dir);
9449 	window->priv->extract_default_dir = _get_default_dir (default_dir);
9450 }
9451 
9452 
9453 GFile *
fr_window_get_extract_default_dir(FrWindow * window)9454 fr_window_get_extract_default_dir (FrWindow *window)
9455 {
9456 	if (window->priv->extract_default_dir == NULL)
9457 		return _g_file_get_home ();
9458 	else
9459 		return  window->priv->extract_default_dir;
9460 }
9461 
9462 
9463 void
fr_window_set_default_dir(FrWindow * window,GFile * default_dir,gboolean freeze)9464 fr_window_set_default_dir (FrWindow *window,
9465 			   GFile    *default_dir,
9466 			   gboolean  freeze)
9467 {
9468 	g_return_if_fail (window != NULL);
9469 	g_return_if_fail (default_dir != NULL);
9470 
9471 	window->priv->freeze_default_dir = freeze;
9472 
9473 	fr_window_set_open_default_dir (window, default_dir);
9474 	fr_window_set_add_default_dir (window, default_dir);
9475 	fr_window_set_extract_default_dir (window, default_dir);
9476 }
9477 
9478 
9479 void
fr_window_set_folders_visibility(FrWindow * window,gboolean value)9480 fr_window_set_folders_visibility (FrWindow   *window,
9481 				  gboolean    value)
9482 {
9483 	g_return_if_fail (window != NULL);
9484 
9485 	window->priv->view_sidebar = value;
9486 	fr_window_update_dir_tree (window);
9487 
9488 	fr_window_set_action_state (window, "view-sidebar", window->priv->view_sidebar);
9489 }
9490 
9491 
9492 void
fr_window_use_progress_dialog(FrWindow * window,gboolean value)9493 fr_window_use_progress_dialog (FrWindow *window,
9494 			       gboolean  value)
9495 {
9496 	window->priv->use_progress_dialog = value;
9497 }
9498 
9499 
9500 /* -- batch mode procedures -- */
9501 
9502 
9503 static void fr_window_batch_exec_current_action (FrWindow *window);
9504 
9505 
9506 static void
fr_window_exec_batch_action(FrWindow * window,FrBatchAction * action)9507 fr_window_exec_batch_action (FrWindow      *window,
9508 			     FrBatchAction *action)
9509 {
9510 	ExtractData   *edata;
9511 	RenameData    *rdata;
9512 	OpenFilesData *odata;
9513 	ConvertData   *cdata;
9514 	EncryptData   *enc_data;
9515 
9516 	switch (action->type) {
9517 	case FR_BATCH_ACTION_LOAD:
9518 		debug (DEBUG_INFO, "[BATCH] LOAD\n");
9519 
9520 		if (! g_file_query_exists (G_FILE (action->data), NULL)) {
9521 			GError *error = NULL;
9522 
9523 			if (! fr_window_archive_new (window, G_FILE (action->data), NULL))
9524 				error = g_error_new_literal (FR_ERROR, FR_ERROR_GENERIC, _("Archive type not supported."));
9525 			_archive_operation_completed (window, FR_ACTION_CREATING_NEW_ARCHIVE, error);
9526 
9527 			_g_error_free (error);
9528 		}
9529 		else
9530 			fr_window_archive_open (window, G_FILE (action->data), GTK_WINDOW (window));
9531 		break;
9532 
9533 	case FR_BATCH_ACTION_ADD:
9534 		debug (DEBUG_INFO, "[BATCH] ADD\n");
9535 
9536 		fr_window_archive_add_dropped_items (window, (GList *) action->data);
9537 		break;
9538 
9539 	case FR_BATCH_ACTION_REMOVE:
9540 		debug (DEBUG_INFO, "[BATCH] REMOVE\n");
9541 		fr_window_archive_remove (window, (GList *) action->data);
9542 		break;
9543 
9544 	case FR_BATCH_ACTION_OPEN:
9545 		debug (DEBUG_INFO, "[BATCH] OPEN\n");
9546 
9547 		dlg_batch_add_files (window, (GList *) action->data);
9548 		break;
9549 
9550 	case FR_BATCH_ACTION_EXTRACT:
9551 		debug (DEBUG_INFO, "[BATCH] EXTRACT\n");
9552 
9553 		edata = action->data;
9554 		fr_window_archive_extract (window,
9555 					   edata->file_list,
9556 					   edata->destination,
9557 					   edata->base_dir,
9558 					   edata->skip_older,
9559 					   edata->overwrite,
9560 					   edata->junk_paths,
9561 					   edata->ask_to_open_destination);
9562 		break;
9563 
9564 	case FR_BATCH_ACTION_EXTRACT_HERE:
9565 		debug (DEBUG_INFO, "[BATCH] EXTRACT HERE\n");
9566 
9567 		edata = action->data;
9568 		fr_window_archive_extract_here (window,
9569 						edata->skip_older,
9570 						edata->overwrite,
9571 						edata->junk_paths);
9572 		break;
9573 
9574 	case FR_BATCH_ACTION_EXTRACT_ASK_OPTIONS:
9575 		debug (DEBUG_INFO, "[BATCH] EXTRACT ASK OPTIONS\n");
9576 
9577 		dlg_extract (NULL, window);
9578 		break;
9579 
9580 	case FR_BATCH_ACTION_RENAME:
9581 		debug (DEBUG_INFO, "[BATCH] RENAME\n");
9582 
9583 		rdata = action->data;
9584 		rename_selection (window,
9585 				  rdata->path_to_rename,
9586 				  rdata->old_name,
9587 				  rdata->new_name,
9588 				  rdata->current_dir,
9589 				  rdata->is_dir,
9590 				  rdata->dir_in_archive,
9591 				  rdata->original_path);
9592 		break;
9593 
9594 	case FR_BATCH_ACTION_PASTE:
9595 		debug (DEBUG_INFO, "[BATCH] PASTE\n");
9596 
9597 		fr_window_paste_from_clipboard_data (window, (FrClipboardData*) action->data);
9598 		break;
9599 
9600 	case FR_BATCH_ACTION_OPEN_FILES:
9601 		debug (DEBUG_INFO, "[BATCH] OPEN FILES\n");
9602 
9603 		odata = action->data;
9604 		fr_window_open_files (window, odata->file_list, odata->ask_application);
9605 		break;
9606 
9607 	case FR_BATCH_ACTION_SAVE_AS:
9608 		debug (DEBUG_INFO, "[BATCH] SAVE_AS\n");
9609 
9610 		cdata = action->data;
9611 		fr_window_archive_save_as (window,
9612 					   cdata->file,
9613 					   cdata->mime_type,
9614 					   cdata->password,
9615 					   cdata->encrypt_header,
9616 					   cdata->volume_size);
9617 		break;
9618 
9619 	case FR_BATCH_ACTION_TEST:
9620 		debug (DEBUG_INFO, "[BATCH] TEST\n");
9621 
9622 		fr_window_archive_test (window);
9623 		break;
9624 
9625 	case FR_BATCH_ACTION_ENCRYPT:
9626 		debug (DEBUG_INFO, "[BATCH] ENCRYPT\n");
9627 
9628 		enc_data = action->data;
9629 		fr_window_archive_encrypt (window,
9630 					   enc_data->password,
9631 					   enc_data->encrypt_header);
9632 		break;
9633 
9634 
9635 	case FR_BATCH_ACTION_CLOSE:
9636 		debug (DEBUG_INFO, "[BATCH] CLOSE\n");
9637 
9638 		fr_window_archive_close (window);
9639 		fr_window_batch_exec_next_action (window);
9640 		break;
9641 
9642 	case FR_BATCH_ACTION_QUIT:
9643 		debug (DEBUG_INFO, "[BATCH] QUIT\n");
9644 
9645 		g_signal_emit (window,
9646 			       fr_window_signals[READY],
9647 			       0,
9648 			       NULL);
9649 
9650 		if ((window->priv->progress_dialog != NULL) && (gtk_widget_get_parent (window->priv->progress_dialog) != GTK_WIDGET (window))) {
9651 			gtk_widget_destroy (window->priv->progress_dialog);
9652 			window->priv->progress_dialog = NULL;
9653 		}
9654 		gtk_widget_destroy (GTK_WIDGET (window));
9655 		break;
9656 
9657 	default:
9658 		break;
9659 	}
9660 }
9661 
9662 
9663 void
fr_window_set_current_action(FrWindow * window,FrBatchActionType action_type,void * data,GFreeFunc free_func)9664 fr_window_set_current_action (FrWindow          *window,
9665 			      FrBatchActionType  action_type,
9666 			      void              *data,
9667 			      GFreeFunc          free_func)
9668 {
9669 	FrBatchAction *action;
9670 
9671 	fr_window_reset_current_action (window);
9672 
9673 	action = &window->priv->current_action;
9674 	action->type = action_type;
9675 	action->data = data;
9676 	action->free_func = free_func;
9677 }
9678 
9679 
9680 void
fr_window_reset_current_action(FrWindow * window)9681 fr_window_reset_current_action (FrWindow *window)
9682 {
9683 	FrBatchAction *action = &window->priv->current_action;
9684 
9685 	if ((action->data != NULL) && (action->free_func != NULL))
9686 		(*action->free_func) (action->data);
9687 	action->type = FR_BATCH_ACTION_NONE;
9688 	action->data = NULL;
9689 	action->free_func = NULL;
9690 }
9691 
9692 
9693 void
fr_window_restart_current_action(FrWindow * window)9694 fr_window_restart_current_action (FrWindow *window)
9695 {
9696 	fr_window_exec_batch_action (window, &window->priv->current_action);
9697 }
9698 
9699 
9700 void
fr_window_batch_append_action(FrWindow * window,FrBatchActionType action,void * data,GFreeFunc free_func)9701 fr_window_batch_append_action (FrWindow          *window,
9702 			       FrBatchActionType  action,
9703 			       void              *data,
9704 			       GFreeFunc          free_func)
9705 {
9706 	FrBatchAction *a_desc;
9707 
9708 	g_return_if_fail (window != NULL);
9709 
9710 	a_desc = g_new0 (FrBatchAction, 1);
9711 	a_desc->type = action;
9712 	a_desc->data = data;
9713 	a_desc->free_func = free_func;
9714 
9715 	window->priv->batch_action_list = g_list_append (window->priv->batch_action_list, a_desc);
9716 }
9717 
9718 
9719 void
fr_window_batch_replace_current_action(FrWindow * window,FrBatchActionType action,void * data,GFreeFunc free_func)9720 fr_window_batch_replace_current_action (FrWindow          *window,
9721 					FrBatchActionType  action,
9722 					void              *data,
9723 					GFreeFunc          free_func)
9724 {
9725 	FrBatchAction *a_desc;
9726 
9727 	g_return_if_fail (window != NULL);
9728 	g_return_if_fail (window->priv->batch_action != NULL);
9729 
9730 	a_desc = g_new0 (FrBatchAction, 1);
9731 	a_desc->type = action;
9732 	a_desc->data = data;
9733 	a_desc->free_func = free_func;
9734 
9735 	fr_batch_action_free ((FrBatchAction *) window->priv->batch_action->data);
9736 	window->priv->batch_action->data = a_desc;
9737 }
9738 
9739 
9740 static void
fr_window_batch_exec_current_action(FrWindow * window)9741 fr_window_batch_exec_current_action (FrWindow *window)
9742 {
9743 	FrBatchAction *action;
9744 
9745 	if (window->priv->batch_action == NULL) {
9746 		fr_window_free_batch_data (window);
9747 		if (window->priv->reload_archive) {
9748 			window->priv->reload_archive = FALSE;
9749 			fr_window_archive_reload (window);
9750 		}
9751 		return;
9752 	}
9753 
9754 	action = (FrBatchAction *) window->priv->batch_action->data;
9755 	fr_window_exec_batch_action (window, action);
9756 }
9757 
9758 
9759 static void
fr_window_batch_exec_next_action(FrWindow * window)9760 fr_window_batch_exec_next_action (FrWindow *window)
9761 {
9762 	if (window->priv->batch_action != NULL)
9763 		window->priv->batch_action = g_list_next (window->priv->batch_action);
9764 	else
9765 		window->priv->batch_action = window->priv->batch_action_list;
9766 	fr_window_batch_exec_current_action (window);
9767 }
9768 
9769 
9770 void
fr_window_batch_start(FrWindow * window)9771 fr_window_batch_start (FrWindow *window)
9772 {
9773 	g_return_if_fail (window != NULL);
9774 
9775 	if (window->priv->batch_mode)
9776 		return;
9777 
9778 	if (window->priv->batch_action_list == NULL)
9779 		return;
9780 
9781 	if (window->priv->progress_dialog != NULL)
9782 		gtk_window_set_title (GTK_WINDOW (window->priv->progress_dialog),
9783 				      window->priv->batch_title);
9784 
9785 	window->priv->batch_mode = TRUE;
9786 	window->priv->batch_action = window->priv->batch_action_list;
9787 	gtk_widget_hide (GTK_WIDGET (window));
9788 
9789 	fr_window_batch_exec_current_action (window);
9790 }
9791 
9792 
9793 void
fr_window_batch_stop(FrWindow * window)9794 fr_window_batch_stop (FrWindow *window)
9795 {
9796 	if (! window->priv->batch_mode) {
9797 		fr_window_free_batch_data (window);
9798 		window->priv->reload_archive = FALSE;
9799 		return;
9800 	}
9801 
9802 	if (! window->priv->showing_error_dialog) {
9803 		g_signal_emit (window,
9804 			       fr_window_signals[READY],
9805 			       0,
9806 			       NULL);
9807 		gtk_widget_destroy (GTK_WIDGET (window));
9808 	}
9809 }
9810 
9811 
9812 void
fr_window_batch_stop_with_error(FrWindow * window,FrAction action,FrErrorType error_type,const char * error_message)9813 fr_window_batch_stop_with_error (FrWindow     *window,
9814 				 FrAction      action,
9815 				 FrErrorType   error_type,
9816 				 const char   *error_message)
9817 {
9818 	GError *error;
9819 
9820 	error = g_error_new_literal (FR_ERROR, error_type, error_message);
9821 	_archive_operation_completed (window, action , error);
9822 
9823 	g_error_free (error);
9824 }
9825 
9826 
9827 void
fr_window_batch_resume(FrWindow * window)9828 fr_window_batch_resume (FrWindow *window)
9829 {
9830 	fr_window_batch_exec_current_action (window);
9831 }
9832 
9833 
9834 gboolean
fr_window_is_batch_mode(FrWindow * window)9835 fr_window_is_batch_mode (FrWindow *window)
9836 {
9837 	return window->priv->batch_mode;
9838 }
9839 
9840 
9841 FrBatchActionType
fr_window_batch_get_current_action_type(FrWindow * window)9842 fr_window_batch_get_current_action_type (FrWindow *window)
9843 {
9844 	FrBatchAction *action;
9845 
9846 	if (! window->priv->batch_mode || (window->priv->batch_action == NULL))
9847 		return FR_BATCH_ACTION_NONE;
9848 
9849 	action = (FrBatchAction *) window->priv->batch_action->data;
9850 	if (action == NULL)
9851 		return FR_BATCH_ACTION_NONE;
9852 
9853 	return action->type;
9854 }
9855 
9856 
9857 void
fr_window_batch_new(FrWindow * window,const char * title)9858 fr_window_batch_new (FrWindow   *window,
9859 		     const char *title)
9860 {
9861 	fr_window_free_batch_data (window);
9862 	g_free (window->priv->batch_title);
9863 	window->priv->batch_title = g_strdup (title);
9864 }
9865 
9866 
9867 const char *
fr_window_batch_get_title(FrWindow * window)9868 fr_window_batch_get_title (FrWindow *window)
9869 {
9870 	return window->priv->batch_title;
9871 }
9872 
9873 
9874 void
fr_window_batch__extract_here(FrWindow * window,GFile * archive,gboolean ask_to_open_destination)9875 fr_window_batch__extract_here (FrWindow *window,
9876 			       GFile    *archive,
9877 			       gboolean  ask_to_open_destination)
9878 {
9879 	g_return_if_fail (window != NULL);
9880 	g_return_if_fail (archive != NULL);
9881 
9882 	fr_window_batch_append_action (window,
9883 				       FR_BATCH_ACTION_LOAD,
9884 				       g_object_ref (archive),
9885 				       (GFreeFunc) g_object_unref);
9886 	fr_window_batch_append_action (window,
9887 				       FR_BATCH_ACTION_EXTRACT_HERE,
9888 				       extract_data_new (window,
9889 							 NULL,
9890 							 NULL,
9891 							 NULL,
9892 							 FALSE,
9893 							 FR_OVERWRITE_ASK,
9894 							 FALSE,
9895 							 ask_to_open_destination,
9896 							 TRUE),
9897 				       (GFreeFunc) extract_data_free);
9898 	fr_window_batch_append_action (window,
9899 				       FR_BATCH_ACTION_CLOSE,
9900 				       NULL,
9901 				       NULL);
9902 }
9903 
9904 
9905 void
fr_window_batch__extract(FrWindow * window,GFile * archive,GFile * destination,gboolean ask_to_open_destination)9906 fr_window_batch__extract (FrWindow  *window,
9907 			  GFile     *archive,
9908 			  GFile     *destination,
9909 			  gboolean   ask_to_open_destination)
9910 {
9911 	g_return_if_fail (window != NULL);
9912 	g_return_if_fail (archive != NULL);
9913 
9914 	fr_window_batch_append_action (window,
9915 				       FR_BATCH_ACTION_LOAD,
9916 				       g_object_ref (archive),
9917 				       (GFreeFunc) g_object_unref);
9918 	if (destination != NULL)
9919 		fr_window_batch_append_action (window,
9920 					       FR_BATCH_ACTION_EXTRACT,
9921 					       extract_data_new (window,
9922 								 NULL,
9923 								 destination,
9924 								 NULL,
9925 								 FALSE,
9926 								 FR_OVERWRITE_ASK,
9927 								 FALSE,
9928 								 ask_to_open_destination,
9929 								 FALSE),
9930 					       (GFreeFunc) extract_data_free);
9931 	else
9932 		fr_window_batch_append_action (window,
9933 					       FR_BATCH_ACTION_EXTRACT_ASK_OPTIONS,
9934 					       NULL,
9935 					       NULL);
9936 	fr_window_batch_append_action (window,
9937 				       FR_BATCH_ACTION_CLOSE,
9938 				       NULL,
9939 				       NULL);
9940 }
9941 
9942 
9943 void
fr_window_batch__add_files(FrWindow * window,GFile * archive,GList * file_list)9944 fr_window_batch__add_files (FrWindow *window,
9945 			    GFile    *archive,
9946 			    GList    *file_list)
9947 {
9948 	window->priv->batch_adding_one_file = (file_list->next == NULL) && (_g_file_query_is_file (file_list->data));
9949 
9950 	if (archive != NULL)
9951 		fr_window_batch_append_action (window,
9952 					       FR_BATCH_ACTION_LOAD,
9953 					       g_object_ref (archive),
9954 					       (GFreeFunc) g_object_unref);
9955 	else
9956 		fr_window_batch_append_action (window,
9957 					       FR_BATCH_ACTION_OPEN,
9958 					       _g_object_list_ref (file_list),
9959 					       (GFreeFunc) _g_object_list_unref);
9960 	fr_window_batch_append_action (window,
9961 				       FR_BATCH_ACTION_ADD,
9962 				       _g_object_list_ref (file_list),
9963 				       (GFreeFunc) _g_object_list_unref);
9964 	fr_window_batch_append_action (window,
9965 				       FR_BATCH_ACTION_CLOSE,
9966 				       NULL,
9967 				       NULL);
9968 }
9969 
9970 
9971 void
fr_window_dnd_extraction_finished(FrWindow * window,gboolean error)9972 fr_window_dnd_extraction_finished (FrWindow *window,
9973 				   gboolean  error)
9974 {
9975 	if (window->priv->dnd_extract_is_running == TRUE) {
9976 		window->priv->dnd_extract_is_running = FALSE;
9977 		window->priv->dnd_extract_finished_with_error = error;
9978 	}
9979 }
9980 
9981 
9982 void
fr_window_extract_archive_and_continue(FrWindow * window,GList * file_list,GFile * destination,const char * base_dir,gboolean skip_older,FrOverwrite overwrite,gboolean junk_paths)9983 fr_window_extract_archive_and_continue (FrWindow      *window,
9984 					GList         *file_list,
9985 					GFile         *destination,
9986 					const char    *base_dir,
9987 					gboolean       skip_older,
9988 					FrOverwrite    overwrite,
9989 					gboolean       junk_paths)
9990 {
9991 	if (fr_window_batch_get_current_action_type (window) == FR_BATCH_ACTION_EXTRACT_ASK_OPTIONS) {
9992 
9993 		/* no need to ask the user the extract options again if the
9994 		 * action is re-executed (for example when asking the password) */
9995 
9996 		fr_window_batch_replace_current_action (window,
9997 							FR_BATCH_ACTION_EXTRACT,
9998 							extract_data_new (window,
9999 									  file_list,
10000 									  destination,
10001 									  base_dir,
10002 									  skip_older,
10003 									  FR_OVERWRITE_ASK,
10004 									  junk_paths,
10005 									  _fr_window_get_ask_to_open_destination (window),
10006 									  FALSE),
10007 							(GFreeFunc) extract_data_free);
10008 		fr_window_batch_resume (window);
10009 	}
10010 	else
10011 		fr_window_archive_extract (window,
10012 					   file_list,
10013 					   destination,
10014 					   base_dir,
10015 					   skip_older,
10016 					   FR_OVERWRITE_ASK,
10017 					   junk_paths,
10018 					   _fr_window_get_ask_to_open_destination (window));
10019 }
10020