2 * Dialog boxes for handling files
4 * $Id: file_dlg.c,v 1.67 2003/12/29 20:05:59 ulfl Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/filesystem.h>
35 #include "gtkglobals.h"
36 #include <epan/resolv.h>
38 #include "filter_prefs.h"
40 #include "simple_dialog.h"
43 #include "dlg_utils.h"
45 #include "compat_macros.h"
48 #include "gtk/color_filters.h"
49 #include "gtk/color_dlg.h"
51 static void file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs);
52 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
53 static void select_file_type_cb(GtkWidget *w, gpointer data);
54 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
55 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
56 static void file_color_import_ok_cb(GtkWidget *w, GtkFileSelection *fs);
57 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
58 static void file_color_export_ok_cb(GtkWidget *w, GtkFileSelection *fs);
59 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
60 static void file_select_ok_cb(GtkWidget *w, gpointer data);
61 static void file_select_cancel_cb(GtkWidget *w, gpointer data);
62 static void file_select_destroy_cb(GtkWidget *win, GtkWidget* file_te);
64 #define E_FILE_M_RESOLVE_KEY "file_dlg_mac_resolve_key"
65 #define E_FILE_N_RESOLVE_KEY "file_dlg_network_resolve_key"
66 #define E_FILE_T_RESOLVE_KEY "file_dlg_transport_resolve_key"
68 #define ARGUMENT_CL "argument_cl"
71 * Keep a static pointer to the current "Save Capture File As" window, if
72 * any, so that if somebody tries to do "File:Save" or "File:Save As"
73 * while there's already a "Save Capture File As" window up, we just pop
74 * up the existing one, rather than creating a new one.
76 static GtkWidget *file_save_as_w;
79 * A generic select_file_cb routine that is intended to be connected to
80 * a Browse button on other dialog boxes. This allows the user to browse
81 * for a file and select it. We fill in the text_entry that is asssociated
82 * with the button that invoked us.
84 * We display the window label specified in our args.
87 select_file_cb(GtkWidget *file_bt, const char *label)
89 GtkWidget *caller = gtk_widget_get_toplevel(file_bt);
90 GtkWidget *fs, *file_te;
92 /* Has a file selection dialog box already been opened for that top-level
94 fs = OBJECT_GET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY);
95 file_te = OBJECT_GET_DATA(file_bt, E_FILE_TE_PTR_KEY);
97 /* Yes. Just re-activate that dialog box. */
98 reactivate_window(fs);
102 fs = file_selection_new (label);
104 /* If we've opened a file, start out by showing the files in the directory
105 in which that file resided. */
107 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
109 OBJECT_SET_DATA(fs, PRINT_FILE_TE_KEY, file_te);
111 /* Set the E_FS_CALLER_PTR_KEY for the new dialog to point to our caller. */
112 OBJECT_SET_DATA(fs, E_FS_CALLER_PTR_KEY, caller);
114 /* Set the E_FILE_SEL_DIALOG_PTR_KEY for the caller to point to us */
115 OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, fs);
117 /* Call a handler when the file selection box is destroyed, so we can inform
118 our caller, if any, that it's been destroyed. */
119 SIGNAL_CONNECT(fs, "destroy", GTK_SIGNAL_FUNC(file_select_destroy_cb),
122 SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->ok_button, "clicked",
123 file_select_ok_cb, fs);
125 /* Connect the cancel_button to destroy the widget */
126 SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->cancel_button, "clicked",
127 file_select_cancel_cb, fs);
129 /* Catch the "key_press_event" signal in the window, so that we can catch
130 the ESC key being pressed and act as if the "Cancel" button had
132 dlg_set_cancel(fs, GTK_FILE_SELECTION(fs)->cancel_button);
138 file_select_ok_cb(GtkWidget *w _U_, gpointer data)
142 f_name = g_strdup(gtk_file_selection_get_filename(
143 GTK_FILE_SELECTION (data)));
145 /* Perhaps the user specified a directory instead of a file.
146 Check whether they did. */
147 if (test_for_directory(f_name) == EISDIR) {
148 /* It's a directory - set the file selection box to display it. */
149 set_last_open_dir(f_name);
151 gtk_file_selection_set_filename(GTK_FILE_SELECTION(data),
156 gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, PRINT_FILE_TE_KEY)),
158 gtk_widget_destroy(GTK_WIDGET(data));
164 file_select_cancel_cb(GtkWidget *w _U_, gpointer data)
166 gtk_widget_destroy(GTK_WIDGET(data));
170 file_select_destroy_cb(GtkWidget *win, GtkWidget* file_te)
174 /* Get the widget that requested that we be popped up.
175 (It should arrange to destroy us if it's destroyed, so
176 that we don't get a pointer to a non-existent window here.) */
177 caller = OBJECT_GET_DATA(win, E_FS_CALLER_PTR_KEY);
179 /* Tell it we no longer exist. */
180 OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, NULL);
182 /* Now nuke this window. */
183 gtk_grab_remove(GTK_WIDGET(win));
184 gtk_widget_destroy(GTK_WIDGET(win));
186 /* Give the focus to the file text entry widget so the user can just press
187 Return to print to the file. */
188 gtk_widget_grab_focus(file_te);
192 * Keep a static pointer to the current "Open Capture File" window, if
193 * any, so that if somebody tries to do "File:Open" while there's already
194 * an "Open Capture File" window up, we just pop up the existing one,
195 * rather than creating a new one.
197 static GtkWidget *file_open_w;
201 file_open_cmd_cb(GtkWidget *w, gpointer data _U_)
203 GtkWidget *main_vb, *filter_hbox, *filter_bt, *filter_te,
204 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
205 #if GTK_MAJOR_VERSION < 2
206 GtkAccelGroup *accel_group;
208 /* No Apply button, and "OK" just sets our text widget, it doesn't
209 activate it (i.e., it doesn't cause us to try to open the file). */
210 static construct_args_t args = {
211 "Ethereal: Read Filter",
216 if (file_open_w != NULL) {
217 /* There's already an "Open Capture File" dialog box; reactivate it. */
218 reactivate_window(file_open_w);
222 file_open_w = file_selection_new ("Ethereal: Open Capture File");
223 SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
225 #if GTK_MAJOR_VERSION < 2
226 /* Accelerator group for the accelerators (or, as they're called in
227 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
228 Ctrl+<key> is an accelerator). */
229 accel_group = gtk_accel_group_new();
230 gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
233 switch (prefs.gui_fileopen_style) {
235 case FO_STYLE_LAST_OPENED:
236 /* The user has specified that we should start out in the last directory
237 we looked in. If we've already opened a file, use its containing
238 directory, if we could determine it, as the directory, otherwise
239 use the "last opened" directory saved in the preferences file if
242 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
246 if (prefs.gui_fileopen_remembered_dir != NULL) {
247 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
248 prefs.gui_fileopen_remembered_dir);
253 case FO_STYLE_SPECIFIED:
254 /* The user has specified that we should always start out in a
255 specified directory; if they've specified that directory,
256 start out by showing the files in that dir. */
257 if (prefs.gui_fileopen_dir[0] != '\0') {
258 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
259 prefs.gui_fileopen_dir);
264 /* Container for each row of widgets */
265 main_vb = gtk_vbox_new(FALSE, 3);
266 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
267 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_open_w)->action_area),
268 main_vb, FALSE, FALSE, 0);
269 gtk_widget_show(main_vb);
271 filter_hbox = gtk_hbox_new(FALSE, 1);
272 gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
273 gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
274 gtk_widget_show(filter_hbox);
276 filter_bt = gtk_button_new_with_label("Filter:");
277 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
278 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
279 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
280 gtk_widget_show(filter_bt);
282 filter_te = gtk_entry_new();
283 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
284 gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
285 gtk_widget_show(filter_te);
287 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
288 E_RFILTER_TE_KEY, filter_te);
290 #if GTK_MAJOR_VERSION < 2
291 m_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
292 "Enable _MAC name resolution", accel_group);
294 m_resolv_cb = gtk_check_button_new_with_mnemonic(
295 "Enable _MAC name resolution");
297 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(m_resolv_cb),
298 g_resolv_flags & RESOLV_MAC);
299 gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
300 gtk_widget_show(m_resolv_cb);
301 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
302 E_FILE_M_RESOLVE_KEY, m_resolv_cb);
304 #if GTK_MAJOR_VERSION < 2
305 n_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
306 "Enable _network name resolution", accel_group);
308 n_resolv_cb = gtk_check_button_new_with_mnemonic(
309 "Enable _network name resolution");
311 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(n_resolv_cb),
312 g_resolv_flags & RESOLV_NETWORK);
313 gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
314 gtk_widget_show(n_resolv_cb);
315 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
316 E_FILE_N_RESOLVE_KEY, n_resolv_cb);
318 #if GTK_MAJOR_VERSION < 2
319 t_resolv_cb = dlg_check_button_new_with_label_with_mnemonic(
320 "Enable _transport name resolution", accel_group);
322 t_resolv_cb = gtk_check_button_new_with_mnemonic(
323 "Enable _transport name resolution");
325 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(t_resolv_cb),
326 g_resolv_flags & RESOLV_TRANSPORT);
327 gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
328 gtk_widget_show(t_resolv_cb);
329 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
330 E_FILE_T_RESOLVE_KEY, t_resolv_cb);
332 /* Connect the ok_button to file_open_ok_cb function and pass along a
333 pointer to the file selection box widget */
334 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
335 file_open_ok_cb, file_open_w);
337 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
338 E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
340 /* Connect the cancel_button to destroy the widget */
341 SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_open_w)->cancel_button,
342 "clicked", (GtkSignalFunc)gtk_widget_destroy,
345 /* Catch the "key_press_event" signal in the window, so that we can catch
346 the ESC key being pressed and act as if the "Cancel" button had
348 dlg_set_cancel(file_open_w, GTK_FILE_SELECTION(file_open_w)->cancel_button);
350 gtk_widget_show(file_open_w);
354 file_open_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
355 gchar *cf_name, *rfilter, *s;
356 GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
357 dfilter_t *rfcode = NULL;
360 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
361 filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
362 rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
363 if (!dfilter_compile(rfilter, &rfcode)) {
365 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
369 /* Perhaps the user specified a directory instead of a file.
370 Check whether they did. */
371 if (test_for_directory(cf_name) == EISDIR) {
372 /* It's a directory - set the file selection box to display that
373 directory, don't try to open the directory as a capture file. */
374 set_last_open_dir(cf_name);
376 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
380 /* Try to open the capture file. */
381 if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
382 /* We couldn't open it; don't dismiss the open dialog box,
383 just leave it around so that the user can, after they
384 dismiss the alert box popped up for the open error,
387 dfilter_free(rfcode);
392 /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
393 it closed the previous capture file, and thus destroyed any
394 previous read filter attached to "cf"). */
395 cfile.rfcode = rfcode;
397 /* Set the global resolving variable */
398 g_resolv_flags = prefs.name_resolve & RESOLV_CONCURRENT;
399 m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
400 g_resolv_flags |= GTK_TOGGLE_BUTTON (m_resolv_cb)->active ? RESOLV_MAC : RESOLV_NONE;
401 n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
402 g_resolv_flags |= GTK_TOGGLE_BUTTON (n_resolv_cb)->active ? RESOLV_NETWORK : RESOLV_NONE;
403 t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
404 g_resolv_flags |= GTK_TOGGLE_BUTTON (t_resolv_cb)->active ? RESOLV_TRANSPORT : RESOLV_NONE;
406 /* We've crossed the Rubicon; get rid of the file selection box. */
407 gtk_widget_hide(GTK_WIDGET (fs));
408 gtk_widget_destroy(GTK_WIDGET (fs));
410 switch (cf_read(&cfile, &err)) {
414 /* Just because we got an error, that doesn't mean we were unable
415 to read any of the file; we handle what we could get from the
420 /* The user bailed out of re-reading the capture file; the
421 capture file has been closed - just free the capture file name
422 string and return (without changing the last containing
428 /* Save the name of the containing directory specified in the path name,
429 if any; we can write over cf_name, which is a good thing, given that
430 "get_dirname()" does write over its argument. */
431 s = get_dirname(cf_name);
432 set_last_open_dir(s);
433 gtk_widget_grab_focus(packet_list);
439 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
441 /* Note that we no longer have a "Open Capture File" dialog box. */
447 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
452 file_save_cmd_cb(GtkWidget *w, gpointer data) {
453 /* If the file's already been saved, do nothing. */
454 if (cfile.user_saved)
457 /* Do a "Save As". */
458 file_save_as_cmd_cb(w, data);
461 /* XXX - can we make these not be static? */
462 static packet_range_t range;
463 static gboolean color_marked;
465 static GtkWidget *filter_cb;
466 static GtkWidget *select_all;
467 static GtkWidget *select_curr;
468 static GtkWidget *select_marked_only;
469 static GtkWidget *select_marked_range;
470 static GtkWidget *select_manual_range;
471 static GtkWidget *range_specs;
472 static GtkWidget *cfmark_cb;
473 static GtkWidget *ft_om;
476 can_save_with_wiretap(int ft)
478 /* To save a file with Wiretap, Wiretap has to handle that format,
479 and its code to handle that format must be able to write a file
480 with this file's encapsulation type. */
481 return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
484 /* Generate a list of the file types we can save this file as.
486 "filetype" is the type it has now.
488 "encap" is the encapsulation for its packets (which could be
489 "unknown" or "per-packet").
491 "filtered" is TRUE if we're to save only the packets that passed
492 the display filter (in which case we have to save it using Wiretap)
493 and FALSE if we're to save the entire file (in which case, if we're
494 saving it in the type it has already, we can just copy it).
496 The same applies for sel_curr, sel_all, sel_m_only, sel_m_range and sel_man_range
499 set_file_type_list(GtkWidget *option_menu)
501 GtkWidget *ft_menu, *ft_menu_item;
504 guint item_to_select;
506 /* Default to the first supported file type, if the file's current
507 type isn't supported. */
510 ft_menu = gtk_menu_new();
512 /* Check all file types. */
514 for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
515 if (!packet_range_process_all(&range) || ft != cfile.cd_t) {
516 /* not all unfiltered packets or a different file type. We have to use Wiretap. */
517 if (!can_save_with_wiretap(ft))
518 continue; /* We can't. */
521 /* OK, we can write it out in this type. */
522 ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
523 if (ft == filetype) {
524 /* Default to the same format as the file, if it's supported. */
525 item_to_select = index;
527 SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
528 GINT_TO_POINTER(ft));
529 gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
530 gtk_widget_show(ft_menu_item);
534 gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
535 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
539 select_file_type_cb(GtkWidget *w _U_, gpointer data)
541 int new_filetype = GPOINTER_TO_INT(data);
543 if (filetype != new_filetype) {
544 /* We can select only the filtered or marked packets to be saved if we can
545 use Wiretap to save the file. */
546 gtk_widget_set_sensitive(filter_cb, can_save_with_wiretap(new_filetype));
547 filetype = new_filetype;
548 file_set_save_marked_sensitive();
553 toggle_filtered_cb(GtkWidget *widget, gpointer data _U_)
555 gboolean new_filtered;
557 new_filtered = GTK_TOGGLE_BUTTON (widget)->active;
559 if (range.process_filtered != new_filtered) {
560 /* They changed the state of the "filtered" button. */
561 range.process_filtered = new_filtered;
562 set_file_type_list(ft_om);
567 toggle_select_all(GtkWidget *widget, gpointer data _U_)
571 new_all = GTK_TOGGLE_BUTTON (widget)->active;
573 if (range.process_all != new_all) {
574 /* They changed the state of the "select-all" button. */
575 range.process_all = new_all;
576 set_file_type_list(ft_om);
581 toggle_select_curr(GtkWidget *widget, gpointer data _U_)
585 new_curr = GTK_TOGGLE_BUTTON (widget)->active;
587 if (range.process_curr != new_curr) {
588 /* They changed the state of the "select-current" button. */
589 range.process_curr = new_curr;
590 set_file_type_list(ft_om);
595 toggle_select_marked_only(GtkWidget *widget, gpointer data _U_)
599 new_marked = GTK_TOGGLE_BUTTON (widget)->active;
601 if (range.process_marked != new_marked) {
602 /* They changed the state of the "marked-only" button. */
603 range.process_marked = new_marked;
604 set_file_type_list(ft_om);
609 toggle_select_marked_range(GtkWidget *widget, gpointer data _U_)
611 gboolean new_marked_range;
613 new_marked_range = GTK_TOGGLE_BUTTON (widget)->active;
615 if (range.process_marked_range != new_marked_range) {
616 /* They changed the state of the "marked-range" button. */
617 range.process_marked_range = new_marked_range;
618 set_file_type_list(ft_om);
623 toggle_select_manual_range(GtkWidget *widget, gpointer data _U_)
625 gboolean new_manual_range;
627 new_manual_range = GTK_TOGGLE_BUTTON (widget)->active;
629 if (range.process_manual_range != new_manual_range) {
630 /* They changed the state of the "manual-range" button. */
631 range.process_manual_range = new_manual_range;
632 set_file_type_list(ft_om);
635 /* Make the entry widget sensitive or insensitive */
636 gtk_widget_set_sensitive(range_specs, range.process_manual_range);
638 /* When selecting manual range, then focus on the entry */
639 if (range.process_manual_range)
640 gtk_widget_grab_focus(range_specs);
645 range_entry(GtkWidget *entry)
648 entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
649 packet_range_convert_str(entry_text);
653 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
655 GtkWidget *ok_bt, *main_vb, *ft_hb, *ft_lb, *range_fr, *range_vb, *range_tb;
656 GtkTooltips *tooltips;
657 gchar label_text[100];
660 #if GTK_MAJOR_VERSION < 2
661 GtkAccelGroup *accel_group;
664 if (file_save_as_w != NULL) {
665 /* There's already an "Save Capture File As" dialog box; reactivate it. */
666 reactivate_window(file_save_as_w);
670 /* Default to saving all packets, in the file's current format. */
671 range.process_all = TRUE;
672 range.process_curr = FALSE;
673 range.process_marked = FALSE;
674 range.process_marked_range = FALSE;
675 range.process_manual_range = FALSE;
676 range.process_filtered = FALSE;
677 filetype = cfile.cd_t;
679 /* init the packet range */
680 packet_range_init(&range);
682 /* Enable tooltips */
683 tooltips = gtk_tooltips_new();
685 file_save_as_w = file_selection_new ("Ethereal: Save Capture File As");
686 SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
688 #if GTK_MAJOR_VERSION < 2
689 accel_group = gtk_accel_group_new();
690 gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
693 /* If we've opened a file, start out by showing the files in the directory
694 in which that file resided. */
696 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w), last_open_dir);
698 /* Connect the ok_button to file_save_as_ok_cb function and pass along a
699 pointer to the file selection box widget */
700 ok_bt = GTK_FILE_SELECTION (file_save_as_w)->ok_button;
701 SIGNAL_CONNECT(ok_bt, "clicked", file_save_as_ok_cb, file_save_as_w);
703 /* Container for each row of widgets */
705 main_vb = gtk_vbox_new(FALSE, 5);
706 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
707 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_save_as_w)->action_area),
708 main_vb, FALSE, FALSE, 0);
709 gtk_widget_show(main_vb);
711 /*** Save Range frame ***/
712 range_fr = gtk_frame_new("Save Range");
713 gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
714 gtk_widget_show(range_fr);
715 range_vb = gtk_vbox_new(FALSE,6);
716 gtk_container_border_width(GTK_CONTAINER(range_vb), 5);
717 gtk_container_add(GTK_CONTAINER(range_fr), range_vb);
718 gtk_widget_show(range_vb);
722 * The argument above could, I guess, be applied to the marked packets,
723 * except that you can't easily tell whether there are any marked
724 * packets, so I could imagine users doing "Save only marked packets"
725 * when there aren't any marked packets, not knowing that they'd
726 * failed to mark them, so I'm more inclined to have the "Save only
727 * marked packets" toggle button enabled only if there are marked
731 /* Save all packets */
732 g_snprintf(label_text, sizeof(label_text), "All _captured %s (%u %s)",
733 plurality(cfile.count, "packet", "packets"), cfile.count, plurality(cfile.count, "packet", "packets"));
734 #if GTK_MAJOR_VERSION < 2
735 select_all = dlg_radio_button_new_with_label_with_mnemonic(NULL, label_text ,accel_group);
737 select_all = gtk_radio_button_new_with_mnemonic(NULL, label_text);
739 gtk_container_add(GTK_CONTAINER(range_vb), select_all);
740 gtk_tooltips_set_tip (tooltips,select_all,("Save all captured packets"), NULL);
741 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_all), FALSE);
742 SIGNAL_CONNECT(select_all, "toggled", toggle_select_all, NULL);
743 gtk_widget_show(select_all);
745 /* Save currently selected */
746 g_snprintf(label_text, sizeof(label_text), "_Selected packet #%u only", cfile.current_frame->num);
747 #if GTK_MAJOR_VERSION < 2
748 select_curr = dlg_radio_button_new_with_label_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
749 label_text,accel_group);
751 select_curr = gtk_radio_button_new_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
754 gtk_container_add(GTK_CONTAINER(range_vb), select_curr);
755 gtk_tooltips_set_tip (tooltips,select_curr,("Save the currently selected packet only"), NULL);
756 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_curr), FALSE);
757 SIGNAL_CONNECT(select_curr, "toggled", toggle_select_curr, NULL);
758 gtk_widget_show(select_curr);
760 /* Save marked packets */
761 g_snprintf(label_text, sizeof(label_text), "_Marked %s only (%u %s)",
762 plurality(cfile.marked_count, "packet", "packets"), cfile.marked_count, plurality(cfile.marked_count, "packet", "packets"));
763 #if GTK_MAJOR_VERSION < 2
764 select_marked_only = dlg_radio_button_new_with_label_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
765 label_text,accel_group);
767 select_marked_only = gtk_radio_button_new_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
770 gtk_container_add(GTK_CONTAINER(range_vb), select_marked_only);
771 gtk_tooltips_set_tip (tooltips,select_marked_only,("Save marked packets only"), NULL);
772 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_marked_only), FALSE);
773 SIGNAL_CONNECT(select_marked_only, "toggled", toggle_select_marked_only, NULL);
774 gtk_widget_show(select_marked_only);
776 /* Save packet range between first and last packet */
777 g_snprintf(label_text, sizeof(label_text), "From first _to last marked packet (%u %s)",
778 range.mark_range, plurality(range.mark_range, "packet", "packets"));
779 #if GTK_MAJOR_VERSION < 2
780 select_marked_range = dlg_radio_button_new_with_label_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
781 label_text,accel_group);
783 select_marked_range = gtk_radio_button_new_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
786 gtk_container_add(GTK_CONTAINER(range_vb), select_marked_range);
787 gtk_tooltips_set_tip (tooltips,select_marked_range,("Save all packets between the first and last marker"), NULL);
788 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_marked_range), FALSE);
789 SIGNAL_CONNECT(select_marked_range, "toggled", toggle_select_marked_range, NULL);
790 gtk_widget_show(select_marked_range);
793 range_tb = gtk_table_new(2, 2, FALSE);
794 gtk_box_pack_start(GTK_BOX(range_vb), range_tb, FALSE, FALSE, 0);
795 gtk_widget_show(range_tb);
797 /* Save a manually provided packet range : -10,30,40-70,80- */
798 g_snprintf(label_text, sizeof(label_text), "Specify a packet _range :");
799 #if GTK_MAJOR_VERSION < 2
800 select_manual_range = dlg_radio_button_new_with_label_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
801 label_text,accel_group);
803 select_manual_range = gtk_radio_button_new_with_mnemonic(gtk_radio_button_group (GTK_RADIO_BUTTON (select_all)),
806 gtk_table_attach_defaults(GTK_TABLE(range_tb), select_manual_range, 0, 1, 1, 2);
807 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_manual_range), FALSE);
808 gtk_tooltips_set_tip (tooltips,select_manual_range,("Save a specified packet range"), NULL);
809 SIGNAL_CONNECT(select_manual_range, "toggled", toggle_select_manual_range, NULL);
810 gtk_widget_show(select_manual_range);
813 range_specs = gtk_entry_new();
814 gtk_entry_set_max_length (GTK_ENTRY (range_specs), 254);
815 gtk_table_attach_defaults(GTK_TABLE(range_tb), range_specs, 1, 2, 1, 2);
816 gtk_tooltips_set_tip (tooltips,range_specs,
817 ("Specify a range of packet numbers : \nExample : 1-10,18,25-100,332-"), NULL);
818 SIGNAL_CONNECT(range_specs,"activate", range_entry, range_specs);
819 gtk_widget_set_sensitive(range_specs, FALSE);
820 gtk_widget_show(range_specs);
823 * XXX - should this be sensitive only if the current display filter
824 * has rejected some packets, so that not all packets are currently
825 * being displayed, and if it has accepted some packets, so that some
826 * packets are currently being displayed?
828 * I'd say "no", as that complicates the UI code, and as one could,
829 * I guess, argue that the user may want to "save all the displayed
830 * packets" even if there aren't any, i.e. save an empty file.
832 #if GTK_MAJOR_VERSION < 2
833 filter_cb = dlg_check_button_new_with_label_with_mnemonic("Apply _display filter",accel_group);
835 filter_cb = gtk_check_button_new_with_mnemonic("Apply _display filter");
837 gtk_container_add(GTK_CONTAINER(range_vb), filter_cb);
838 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_cb), FALSE);
839 SIGNAL_CONNECT(filter_cb, "toggled", toggle_filtered_cb, NULL);
840 gtk_widget_set_sensitive(filter_cb, can_save_with_wiretap(filetype));
841 gtk_widget_show(filter_cb);
845 ft_hb = gtk_hbox_new(FALSE, 3);
846 gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
847 gtk_widget_show(ft_hb);
849 ft_lb = gtk_label_new("File type:");
850 gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
851 gtk_widget_show(ft_lb);
853 ft_om = gtk_option_menu_new();
855 /* Generate the list of file types we can save. */
856 set_file_type_list(ft_om);
857 gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
858 gtk_widget_show(ft_om);
861 * Set the sensitivity of the "Save only marked packets" toggle
864 * This has to be done after we create the file type menu option,
865 * as the routine that sets it also sets that menu.
867 file_set_save_marked_sensitive();
869 /* Connect the cancel_button to destroy the widget */
870 SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_save_as_w)->cancel_button,
871 "clicked", (GtkSignalFunc)gtk_widget_destroy,
874 /* Catch the "key_press_event" signal in the window, so that we can catch
875 the ESC key being pressed and act as if the "Cancel" button had
877 dlg_set_cancel(file_save_as_w, GTK_FILE_SELECTION(file_save_as_w)->cancel_button);
879 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w), "");
881 gtk_widget_show(file_save_as_w);
885 * Set the "Save only marked packets" toggle button as appropriate for
886 * the current output file type and count of marked packets.
888 * Called when the "Save As..." dialog box is created and when either
889 * the file type or the marked count changes.
892 file_set_save_marked_sensitive(void)
894 if (file_save_as_w == NULL) {
895 /* We don't currently have a "Save As..." dialog box up. */
899 /* We can request that only the marked packets be saved only if we
900 can use Wiretap to save the file and if there *are* marked packets. */
901 if (can_save_with_wiretap(filetype) && cfile.marked_count != 0) {
902 gtk_widget_set_sensitive(select_marked_only, TRUE);
903 gtk_widget_set_sensitive(select_marked_range, TRUE);
906 /* Force the "Save only marked packets" toggle to "false", turn
907 off the flag it controls, and update the list of types we can
909 range.process_marked = FALSE;
910 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_marked_only), FALSE);
911 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(select_marked_range), FALSE);
912 set_file_type_list(ft_om);
913 gtk_widget_set_sensitive(select_marked_only, FALSE);
914 gtk_widget_set_sensitive(select_marked_range, FALSE);
919 file_save_as_ok_cb(GtkWidget *w _U_, GtkFileSelection *fs) {
923 /* obtain the range specifications in case we selected manual range */
924 if (range.process_manual_range) {
925 range_entry(range_specs);
928 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
930 /* Perhaps the user specified a directory instead of a file.
931 Check whether they did. */
932 if (test_for_directory(cf_name) == EISDIR) {
933 /* It's a directory - set the file selection box to display that
934 directory, and leave the selection box displayed. */
935 set_last_open_dir(cf_name);
937 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
941 /* Write out the packets (all, or only the ones that are currently
942 displayed or marked) to the file with the specified name. */
944 if (! cf_save(cf_name, &cfile, &range, filetype)) {
945 /* The write failed; don't dismiss the open dialog box,
946 just leave it around so that the user can, after they
947 dismiss the alert box popped up for the error, try again. */
952 /* The write succeeded; get rid of the file selection box. */
953 gtk_widget_hide(GTK_WIDGET (fs));
954 gtk_widget_destroy(GTK_WIDGET (fs));
956 /* Save the directory name for future file dialogs. */
957 dirname = get_dirname(cf_name); /* Overwrites cf_name */
958 set_last_open_dir(dirname);
963 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
965 /* Note that we no longer have a "Save Capture File As" dialog box. */
966 file_save_as_w = NULL;
969 /* Reload a file using the current read and display filters */
971 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
973 gboolean is_tempfile;
976 /* If the file could be opened, "cf_open()" calls "cf_close()"
977 to get rid of state for the old capture file before filling in state
978 for the new capture file. "cf_close()" will remove the file if
979 it's a temporary file; we don't want that to happen (for one thing,
980 it'd prevent subsequent reopens from working). Remember whether it's
981 a temporary file, mark it as not being a temporary file, and then
982 reopen it as the type of file it was.
984 Also, "cf_close()" will free "cfile.filename", so we must make
985 a copy of it first. */
986 filename = g_strdup(cfile.filename);
987 is_tempfile = cfile.is_tempfile;
988 cfile.is_tempfile = FALSE;
989 if (cf_open(filename, is_tempfile, &cfile) == 0) {
990 switch (cf_read(&cfile, &err)) {
994 /* Just because we got an error, that doesn't mean we were unable
995 to read any of the file; we handle what we could get from the
1000 /* The user bailed out of re-reading the capture file; the
1001 capture file has been closed - just free the capture file name
1002 string and return (without changing the last containing
1008 /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
1009 Instead, the file was left open, so we should restore "cfile.is_tempfile"
1012 XXX - change the menu? Presumably "cf_open()" will do that;
1013 make sure it does! */
1014 cfile.is_tempfile = is_tempfile;
1016 /* "cf_open()" made a copy of the file name we handed it, so
1017 we should free up our copy. */
1021 /******************** Color Filters *********************************/
1023 * Keep a static pointer to the current "Color Export" window, if
1024 * any, so that if somebody tries to do "Export"
1025 * while there's already a "Color Export" window up, we just pop
1026 * up the existing one, rather than creating a new one.
1028 static GtkWidget *file_color_import_w;
1030 /* sets the file path to the global color filter file.
1031 WARNING: called by both the import and the export dialog.
1034 color_global_cb(GtkWidget *widget _U_, gpointer data)
1036 GtkWidget *fs_widget = data;
1040 /* decide what file to open (from dfilter code) */
1041 path = get_datafile_path("colorfilters");
1043 gtk_file_selection_set_filename (GTK_FILE_SELECTION(fs_widget), path);
1045 g_free((gchar *)path);
1048 /* Import color filters */
1050 file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
1052 GtkWidget *main_vb, *cfglobal_but;
1053 #if GTK_MAJOR_VERSION < 2
1054 GtkAccelGroup *accel_group;
1056 /* No Apply button, and "OK" just sets our text widget, it doesn't
1057 activate it (i.e., it doesn't cause us to try to open the file). */
1059 if (file_color_import_w != NULL) {
1060 /* There's already an "Import Color Filters" dialog box; reactivate it. */
1061 reactivate_window(file_color_import_w);
1065 file_color_import_w = gtk_file_selection_new ("Ethereal: Import Color Filters");
1066 SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1068 #if GTK_MAJOR_VERSION < 2
1069 /* Accelerator group for the accelerators (or, as they're called in
1070 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1071 Ctrl+<key> is an accelerator). */
1072 accel_group = gtk_accel_group_new();
1073 gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1076 /* If we've opened a file, start out by showing the files in the directory
1077 in which that file resided. */
1079 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_import_w), last_open_dir);
1081 /* Container for each row of widgets */
1082 main_vb = gtk_vbox_new(FALSE, 3);
1083 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1084 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_import_w)->action_area),
1085 main_vb, FALSE, FALSE, 0);
1086 gtk_widget_show(main_vb);
1089 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1090 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1091 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1092 gtk_widget_show(cfglobal_but);
1094 /* Connect the ok_button to file_open_ok_cb function and pass along a
1095 pointer to the file selection box widget */
1096 SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1097 file_color_import_ok_cb, file_color_import_w);
1099 OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
1102 /* Connect the cancel_button to destroy the widget */
1103 SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_import_w)->cancel_button,
1104 "clicked", (GtkSignalFunc)gtk_widget_destroy,
1105 file_color_import_w);
1107 /* Catch the "key_press_event" signal in the window, so that we can catch
1108 the ESC key being pressed and act as if the "Cancel" button had
1110 dlg_set_cancel(file_color_import_w, GTK_FILE_SELECTION(file_color_import_w)->cancel_button);
1112 gtk_widget_show(file_color_import_w);
1116 file_color_import_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
1120 argument = OBJECT_GET_DATA(w, ARGUMENT_CL); /* to be passed back into read_other_filters */
1122 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
1123 /* Perhaps the user specified a directory instead of a file.
1124 Check whether they did. */
1125 if (test_for_directory(cf_name) == EISDIR) {
1126 /* It's a directory - set the file selection box to display that
1127 directory, don't try to open the directory as a capture file. */
1128 set_last_open_dir(cf_name);
1130 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1134 /* Try to open the capture file. */
1136 if (!read_other_filters(cf_name, argument)) {
1137 /* We couldn't open it; don't dismiss the open dialog box,
1138 just leave it around so that the user can, after they
1139 dismiss the alert box popped up for the open error,
1145 /* We've crossed the Rubicon; get rid of the file selection box. */
1146 gtk_widget_hide(GTK_WIDGET (fs));
1147 gtk_widget_destroy(GTK_WIDGET (fs));
1149 /* Save the name of the containing directory specified in the path name,
1150 if any; we can write over cf_name, which is a good thing, given that
1151 "get_dirname()" does write over its argument. */
1152 s = get_dirname(cf_name);
1153 set_last_open_dir(s);
1154 gtk_widget_grab_focus(packet_list);
1160 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1162 /* Note that we no longer have a "Open Capture File" dialog box. */
1163 file_color_import_w = NULL;
1166 static GtkWidget *file_color_export_w;
1168 * Set the "Export only marked filters" toggle button as appropriate for
1169 * the current output file type and count of marked filters.
1171 * Called when the "Export" dialog box is created and when the marked
1175 color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
1177 if (file_color_export_w == NULL) {
1178 /* We don't currently have an "Export" dialog box up. */
1182 /* We can request that only the marked filters be saved only if
1183 there *are* marked filters. */
1184 if (color_marked_count() != 0)
1185 gtk_widget_set_sensitive(cfmark_cb, TRUE);
1187 /* Force the "Export only marked filters" toggle to "false", turn
1188 off the flag it controls. */
1189 color_marked = FALSE;
1190 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1191 gtk_widget_set_sensitive(cfmark_cb, FALSE);
1196 color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
1198 color_marked = GTK_TOGGLE_BUTTON (widget)->active;
1202 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1204 GtkWidget *ok_bt, *main_vb, *cfglobal_but;
1206 if (file_color_export_w != NULL) {
1207 /* There's already an "Color Filter Export" dialog box; reactivate it. */
1208 reactivate_window(file_color_export_w);
1212 /* Default to saving all packets, in the file's current format. */
1213 color_marked = FALSE;
1214 filetype = cfile.cd_t;
1216 file_color_export_w = gtk_file_selection_new ("Ethereal: Export Color Filters");
1217 SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1219 /* If we've opened a file, start out by showing the files in the directory
1220 in which that file resided. */
1222 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), last_open_dir);
1224 /* Connect the ok_button to file_export_ok_cb function and pass along a
1225 pointer to the file selection box widget */
1226 ok_bt = GTK_FILE_SELECTION (file_color_export_w)->ok_button;
1227 SIGNAL_CONNECT(ok_bt, "clicked", file_color_export_ok_cb, file_color_export_w);
1229 /* Container for each row of widgets */
1230 main_vb = gtk_vbox_new(FALSE, 3);
1231 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1232 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_export_w)->action_area),
1233 main_vb, FALSE, FALSE, 0);
1234 gtk_widget_show(main_vb);
1236 cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
1237 gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
1238 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1239 SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
1240 gtk_widget_show(cfmark_cb);
1241 color_set_export_marked_sensitive(cfmark_cb);
1243 cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1244 gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1245 SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1246 gtk_widget_show(cfglobal_but);
1248 /* Connect the cancel_button to destroy the widget */
1249 SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_export_w)->cancel_button,
1250 "clicked", (GtkSignalFunc)gtk_widget_destroy,
1251 file_color_export_w);
1253 /* Catch the "key_press_event" signal in the window, so that we can catch
1254 the ESC key being pressed and act as if the "Cancel" button had
1256 dlg_set_cancel(file_color_export_w, GTK_FILE_SELECTION(file_color_export_w)->cancel_button);
1258 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1260 gtk_widget_show(file_color_export_w);
1264 file_color_export_ok_cb(GtkWidget *w _U_, GtkFileSelection *fs) {
1268 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1270 /* Perhaps the user specified a directory instead of a file.
1271 Check whether they did. */
1272 if (test_for_directory(cf_name) == EISDIR) {
1273 /* It's a directory - set the file selection box to display that
1274 directory, and leave the selection box displayed. */
1275 set_last_open_dir(cf_name);
1277 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1281 /* Write out the filters (all, or only the ones that are currently
1282 displayed or marked) to the file with the specified name. */
1284 if (!write_other_filters(cf_name, color_marked))
1286 /* The write failed; don't dismiss the open dialog box,
1287 just leave it around so that the user can, after they
1288 dismiss the alert box popped up for the error, try again. */
1294 /* The write succeeded; get rid of the file selection box. */
1295 gtk_widget_hide(GTK_WIDGET (fs));
1296 gtk_widget_destroy(GTK_WIDGET (fs));
1298 /* Save the directory name for future file dialogs. */
1299 dirname = get_dirname(cf_name); /* Overwrites cf_name */
1300 set_last_open_dir(dirname);
1305 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1307 file_color_export_w = NULL;