Use the new GtkFileChooserDialog when built with gtk+ 2.4
[metze/wireshark/wip.git] / gtk / file_dlg.c
1 /* file_dlg.c
2  * Dialog boxes for handling files
3  *
4  * $Id: file_dlg.c,v 1.99 2004/03/27 11:16:58 oabad Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30
31 #include "range.h"
32 #include <epan/filesystem.h>
33
34 #include "globals.h"
35 #include "gtkglobals.h"
36 #include <epan/resolv.h>
37 #include "keys.h"
38 #include "filter_prefs.h"
39 #include "ui_util.h"
40 #include "alert_box.h"
41 #include "simple_dialog.h"
42 #include "menu.h"
43 #include "file_dlg.h"
44 #include "dlg_utils.h"
45 #include "main.h"
46 #include "compat_macros.h"
47 #include "prefs.h"
48 #include "recent.h"
49 #include "color.h"
50 #include "../ui_util.h"
51 #include "gtk/color_filters.h"
52 #include "gtk/color_dlg.h"
53 #ifdef HAVE_LIBPCAP
54 #include "capture_dlg.h"
55 #endif
56
57
58 static void file_open_ok_cb(GtkWidget *w, gpointer fs);
59 static void file_open_destroy_cb(GtkWidget *win, gpointer user_data);
60 static void select_file_type_cb(GtkWidget *w, gpointer data);
61 static void file_save_as_ok_cb(GtkWidget *w, gpointer fs);
62 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
63 static void file_color_import_ok_cb(GtkWidget *w, gpointer fs);
64 static void file_color_import_destroy_cb(GtkWidget *win, gpointer user_data);
65 static void file_color_export_ok_cb(GtkWidget *w, gpointer fs);
66 static void file_color_export_destroy_cb(GtkWidget *win, gpointer user_data);
67 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || GTK_MAJOR_VERSION < 2
68 static void file_select_ok_cb(GtkWidget *w, gpointer data);
69 static void file_select_cancel_cb(GtkWidget *w, gpointer data);
70 #endif
71 static void file_select_destroy_cb(GtkWidget *win, GtkWidget* file_te);
72 static void toggle_captured_cb(GtkWidget *widget, gpointer data _U_);
73
74 #define E_FILE_M_RESOLVE_KEY      "file_dlg_mac_resolve_key"
75 #define E_FILE_N_RESOLVE_KEY      "file_dlg_network_resolve_key"
76 #define E_FILE_T_RESOLVE_KEY      "file_dlg_transport_resolve_key"
77
78 #define ARGUMENT_CL "argument_cl"
79
80 /*
81  * Keep a static pointer to the current "Save Capture File As" window, if
82  * any, so that if somebody tries to do "File:Save" or "File:Save As"
83  * while there's already a "Save Capture File As" window up, we just pop
84  * up the existing one, rather than creating a new one.
85  */
86 static GtkWidget *file_save_as_w;
87
88 /*
89  * A generic select_file_cb routine that is intended to be connected to
90  * a Browse button on other dialog boxes. This allows the user to browse
91  * for a file and select it. We fill in the text_entry that is asssociated
92  * with the button that invoked us. 
93  *
94  * We display the window label specified in our args.
95  */
96 void
97 select_file_cb(GtkWidget *file_bt, const char *label)
98 {
99   GtkWidget *caller = gtk_widget_get_toplevel(file_bt);
100   GtkWidget *fs, *file_te;
101   gchar     *f_name;
102
103   /* Has a file selection dialog box already been opened for that top-level
104      widget? */
105   fs = OBJECT_GET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY);
106   file_te = OBJECT_GET_DATA(file_bt, E_FILE_TE_PTR_KEY);
107   if (fs != NULL) {
108     /* Yes.  Just re-activate that dialog box. */
109     reactivate_window(fs);
110     return;
111   }
112
113 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
114   fs = file_selection_new(label, GTK_FILE_CHOOSER_ACTION_SAVE);
115 #else
116   fs = file_selection_new(label);
117 #endif
118
119   /* If we've opened a file, start out by showing the files in the directory
120      in which that file resided. */
121 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
122   if (last_open_dir)
123     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs), last_open_dir);
124 #else
125   if (last_open_dir)
126     gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
127 #endif
128
129   OBJECT_SET_DATA(fs, PRINT_FILE_TE_KEY, file_te);
130
131   /* Set the E_FS_CALLER_PTR_KEY for the new dialog to point to our caller. */
132   OBJECT_SET_DATA(fs, E_FS_CALLER_PTR_KEY, caller);
133
134   /* Set the E_FILE_SEL_DIALOG_PTR_KEY for the caller to point to us */
135   OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, fs);
136
137   /* Call a handler when the file selection box is destroyed, so we can inform
138      our caller, if any, that it's been destroyed. */
139   SIGNAL_CONNECT(fs, "destroy", GTK_SIGNAL_FUNC(file_select_destroy_cb), 
140                  file_te);
141
142 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
143   if (gtk_dialog_run(GTK_DIALOG(fs)) == GTK_RESPONSE_ACCEPT)
144   {
145       f_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
146       gtk_entry_set_text(GTK_ENTRY(file_te), f_name);
147       g_free(f_name);
148   }
149   gtk_widget_destroy(fs);
150 #else
151   SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->ok_button, "clicked", 
152                  file_select_ok_cb, fs);
153
154   /* Connect the cancel_button to destroy the widget */
155   SIGNAL_CONNECT(GTK_FILE_SELECTION(fs)->cancel_button, "clicked",
156                  file_select_cancel_cb, fs);
157
158   /* Catch the "key_press_event" signal in the window, so that we can catch
159      the ESC key being pressed and act as if the "Cancel" button had
160      been selected. */
161   dlg_set_cancel(fs, GTK_FILE_SELECTION(fs)->cancel_button);
162
163   gtk_widget_show(fs);
164 #endif
165 }
166
167 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4) || GTK_MAJOR_VERSION < 2
168 static void
169 file_select_ok_cb(GtkWidget *w _U_, gpointer data)
170 {
171   gchar     *f_name;
172
173   f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));
174
175   /* Perhaps the user specified a directory instead of a file.
176      Check whether they did. */
177   if (test_for_directory(f_name) == EISDIR) {
178         /* It's a directory - set the file selection box to display it. */
179         set_last_open_dir(f_name);
180         g_free(f_name);
181         gtk_file_selection_set_filename(GTK_FILE_SELECTION(data),
182                                         last_open_dir);
183         return;
184   }
185
186   gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, PRINT_FILE_TE_KEY)),
187                      f_name);
188   gtk_widget_destroy(GTK_WIDGET(data));
189
190   g_free(f_name);
191 }
192
193 static void
194 file_select_cancel_cb(GtkWidget *w _U_, gpointer data)
195 {
196   gtk_widget_destroy(GTK_WIDGET(data));
197 }
198 #endif
199
200 static void
201 file_select_destroy_cb(GtkWidget *win, GtkWidget* file_te)
202 {
203   GtkWidget *caller;
204
205   /* Get the widget that requested that we be popped up.
206      (It should arrange to destroy us if it's destroyed, so
207      that we don't get a pointer to a non-existent window here.) */
208   caller = OBJECT_GET_DATA(win, E_FS_CALLER_PTR_KEY);
209
210   /* Tell it we no longer exist. */
211   OBJECT_SET_DATA(caller, E_FILE_SEL_DIALOG_PTR_KEY, NULL);
212
213   /* Now nuke this window. */
214   gtk_grab_remove(GTK_WIDGET(win));
215   gtk_widget_destroy(GTK_WIDGET(win));
216
217   /* Give the focus to the file text entry widget so the user can just press
218      Return to print to the file. */
219   gtk_widget_grab_focus(file_te);
220 }
221
222 /*
223  * Keep a static pointer to the current "Open Capture File" window, if
224  * any, so that if somebody tries to do "File:Open" while there's already
225  * an "Open Capture File" window up, we just pop up the existing one,
226  * rather than creating a new one.
227  */
228 static GtkWidget *file_open_w;
229
230 /* Open a file */
231 void
232 file_open_cmd(GtkWidget *w)
233 {
234   GtkWidget     *main_vb, *filter_hbox, *filter_bt, *filter_te,
235                 *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
236 #if GTK_MAJOR_VERSION < 2
237   GtkAccelGroup *accel_group;
238 #endif
239   /* No Apply button, and "OK" just sets our text widget, it doesn't
240      activate it (i.e., it doesn't cause us to try to open the file). */
241   static construct_args_t args = {
242         "Ethereal: Read Filter",
243         FALSE,
244         FALSE
245   };
246
247   if (file_open_w != NULL) {
248     /* There's already an "Open Capture File" dialog box; reactivate it. */
249     reactivate_window(file_open_w);
250     return;
251   }
252
253 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
254   file_open_w = file_selection_new("Ethereal: Open Capture File",
255                                    GTK_FILE_CHOOSER_ACTION_OPEN);
256 #else
257   file_open_w = file_selection_new("Ethereal: Open Capture File");
258 #endif
259   SIGNAL_CONNECT(file_open_w, "destroy", file_open_destroy_cb, NULL);
260
261 #if GTK_MAJOR_VERSION < 2
262   /* Accelerator group for the accelerators (or, as they're called in
263      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
264      Ctrl+<key> is an accelerator). */
265   accel_group = gtk_accel_group_new();
266   gtk_window_add_accel_group(GTK_WINDOW(file_open_w), accel_group);
267 #endif
268
269   switch (prefs.gui_fileopen_style) {
270
271   case FO_STYLE_LAST_OPENED:
272     /* The user has specified that we should start out in the last directory
273        we looked in.  If we've already opened a file, use its containing
274        directory, if we could determine it, as the directory, otherwise
275        use the "last opened" directory saved in the preferences file if
276        there was one. */
277 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
278     if (last_open_dir) {
279       gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_open_w),
280                                           last_open_dir);
281     }
282 #else
283     if (last_open_dir) {
284       gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
285                                       last_open_dir);
286     }
287 #endif
288     break;
289
290   case FO_STYLE_SPECIFIED:
291     /* The user has specified that we should always start out in a
292        specified directory; if they've specified that directory,
293        start out by showing the files in that dir. */
294 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
295     if (prefs.gui_fileopen_dir[0] != '\0') {
296       gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_open_w),
297                                           prefs.gui_fileopen_dir);
298     }
299 #else
300     if (prefs.gui_fileopen_dir[0] != '\0') {
301       gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_open_w),
302                                       prefs.gui_fileopen_dir);
303     }
304 #endif
305     break;
306   }
307     
308   /* Container for each row of widgets */
309   main_vb = gtk_vbox_new(FALSE, 3);
310   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
311 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
312   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_open_w), main_vb);
313 #else
314   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_open_w)->action_area),
315     main_vb, FALSE, FALSE, 0);
316 #endif
317   gtk_widget_show(main_vb);
318
319   filter_hbox = gtk_hbox_new(FALSE, 1);
320   gtk_container_border_width(GTK_CONTAINER(filter_hbox), 0);
321   gtk_box_pack_start(GTK_BOX(main_vb), filter_hbox, FALSE, FALSE, 0);
322   gtk_widget_show(filter_hbox);
323
324   filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
325   SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
326   SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
327   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_bt, FALSE, TRUE, 0);
328   gtk_widget_show(filter_bt);
329
330   filter_te = gtk_entry_new();
331   OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
332   gtk_box_pack_start(GTK_BOX(filter_hbox), filter_te, TRUE, TRUE, 3);
333   SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
334   gtk_widget_show(filter_te);
335
336 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
337   OBJECT_SET_DATA(file_open_w, E_RFILTER_TE_KEY, filter_te);
338 #else
339   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
340                   E_RFILTER_TE_KEY, filter_te);
341 #endif
342
343   m_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _MAC name resolution", accel_group);
344   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_resolv_cb),
345         g_resolv_flags & RESOLV_MAC);
346   gtk_box_pack_start(GTK_BOX(main_vb), m_resolv_cb, FALSE, FALSE, 0);
347 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
348   OBJECT_SET_DATA(file_open_w,
349                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
350 #else
351   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
352                   E_FILE_M_RESOLVE_KEY, m_resolv_cb);
353 #endif
354   gtk_widget_show(m_resolv_cb);
355
356   n_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _network name resolution", accel_group);
357   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(n_resolv_cb),
358         g_resolv_flags & RESOLV_NETWORK);
359   gtk_box_pack_start(GTK_BOX(main_vb), n_resolv_cb, FALSE, FALSE, 0);
360   gtk_widget_show(n_resolv_cb);
361 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
362   OBJECT_SET_DATA(file_open_w, E_FILE_N_RESOLVE_KEY, n_resolv_cb);
363 #else
364   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
365                   E_FILE_N_RESOLVE_KEY, n_resolv_cb);
366 #endif
367
368   t_resolv_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Enable _transport name resolution", accel_group);
369   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_resolv_cb),
370         g_resolv_flags & RESOLV_TRANSPORT);
371   gtk_box_pack_start(GTK_BOX(main_vb), t_resolv_cb, FALSE, FALSE, 0);
372   gtk_widget_show(t_resolv_cb);
373 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
374   OBJECT_SET_DATA(file_open_w, E_FILE_T_RESOLVE_KEY, t_resolv_cb);
375 #else
376   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
377                   E_FILE_T_RESOLVE_KEY, t_resolv_cb);
378 #endif
379
380 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
381   OBJECT_SET_DATA(file_open_w, E_DFILTER_TE_KEY,
382                   OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
383   if (gtk_dialog_run(GTK_DIALOG(file_open_w)) == GTK_RESPONSE_ACCEPT)
384   {
385     file_open_ok_cb(file_open_w, file_open_w);
386   }
387   else gtk_widget_destroy(file_open_w);
388 #else
389   /* Connect the ok_button to file_open_ok_cb function and pass along a
390      pointer to the file selection box widget */
391   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_open_w)->ok_button, "clicked",
392                  file_open_ok_cb, file_open_w);
393
394   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_open_w)->ok_button,
395                   E_DFILTER_TE_KEY, OBJECT_GET_DATA(w, E_DFILTER_TE_KEY));
396
397   /* Connect the cancel_button to destroy the widget */
398   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_open_w)->cancel_button,
399                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
400                         file_open_w);
401
402   /* Catch the "key_press_event" signal in the window, so that we can catch
403      the ESC key being pressed and act as if the "Cancel" button had
404      been selected. */
405   dlg_set_cancel(file_open_w, GTK_FILE_SELECTION(file_open_w)->cancel_button);
406
407   gtk_widget_show(file_open_w);
408 #endif
409 }
410
411 void file_open_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
412 {
413     switch(btn) {
414     case(ESD_BTN_YES):
415         /* save file first */
416         file_save_as_cmd(after_save_open_dialog, data);
417         break;
418     case(ESD_BTN_NO):
419         cf_close(&cfile);
420         file_open_cmd(data);
421         break;
422     case(ESD_BTN_CANCEL):
423         break;
424     default:
425         g_assert_not_reached();
426     }
427 }
428
429 void
430 file_open_cmd_cb(GtkWidget *widget, gpointer data _U_) {
431   gpointer  dialog;
432
433   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
434     /* user didn't saved his current file, ask him */
435     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
436                 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
437                 "If you open a new capture file without saving, your capture data will be discarded.");
438     simple_dialog_set_cb(dialog, file_open_answered_cb, widget);
439   } else {
440     /* unchanged file, just open a new one */
441     file_open_cmd(widget);
442   }
443 }
444
445 static void
446 file_open_ok_cb(GtkWidget *w, gpointer fs) {
447   gchar     *cf_name, *rfilter, *s;
448   GtkWidget *filter_te, *m_resolv_cb, *n_resolv_cb, *t_resolv_cb;
449   dfilter_t *rfcode = NULL;
450   int        err;
451
452 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
453   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
454 #else
455   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
456 #endif
457   filter_te = OBJECT_GET_DATA(w, E_RFILTER_TE_KEY);
458   rfilter = (gchar *)gtk_entry_get_text(GTK_ENTRY(filter_te));
459   if (!dfilter_compile(rfilter, &rfcode)) {
460     bad_dfilter_alert_box(rfilter);
461     g_free(cf_name);
462     return;
463   }
464
465   /* Perhaps the user specified a directory instead of a file.
466      Check whether they did. */
467   if (test_for_directory(cf_name) == EISDIR) {
468         /* It's a directory - set the file selection box to display that
469            directory, don't try to open the directory as a capture file. */
470         set_last_open_dir(cf_name);
471         g_free(cf_name);
472         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
473         return;
474   }
475
476   /* Try to open the capture file. */
477   if ((err = cf_open(cf_name, FALSE, &cfile)) != 0) {
478     /* We couldn't open it; don't dismiss the open dialog box,
479        just leave it around so that the user can, after they
480        dismiss the alert box popped up for the open error,
481        try again. */
482     if (rfcode != NULL)
483       dfilter_free(rfcode);
484     g_free(cf_name);
485     return;
486   }
487
488   /* Attach the new read filter to "cf" ("cf_open()" succeeded, so
489      it closed the previous capture file, and thus destroyed any
490      previous read filter attached to "cf"). */
491   cfile.rfcode = rfcode;
492
493   /* Set the global resolving variable */
494   g_resolv_flags = prefs.name_resolve & RESOLV_CONCURRENT;
495   m_resolv_cb = OBJECT_GET_DATA(w, E_FILE_M_RESOLVE_KEY);
496   g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (m_resolv_cb)) ? RESOLV_MAC : RESOLV_NONE;
497   n_resolv_cb = OBJECT_GET_DATA(w, E_FILE_N_RESOLVE_KEY);
498   g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (n_resolv_cb)) ? RESOLV_NETWORK : RESOLV_NONE;
499   t_resolv_cb = OBJECT_GET_DATA(w, E_FILE_T_RESOLVE_KEY);
500   g_resolv_flags |= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (t_resolv_cb)) ? RESOLV_TRANSPORT : RESOLV_NONE;
501
502   /* We've crossed the Rubicon; get rid of the file selection box. */
503   gtk_widget_hide(GTK_WIDGET (fs));
504   gtk_widget_destroy(GTK_WIDGET (fs));
505
506   switch (cf_read(&cfile)) {
507
508   case READ_SUCCESS:
509   case READ_ERROR:
510     /* Just because we got an error, that doesn't mean we were unable
511        to read any of the file; we handle what we could get from the
512        file. */
513     break;
514
515   case READ_ABORTED:
516     /* The user bailed out of re-reading the capture file; the
517        capture file has been closed - just free the capture file name
518        string and return (without changing the last containing
519        directory). */
520     g_free(cf_name);
521     return;
522   }
523
524   /* Save the name of the containing directory specified in the path name,
525      if any; we can write over cf_name, which is a good thing, given that
526      "get_dirname()" does write over its argument. */
527   s = get_dirname(cf_name);
528   set_last_open_dir(s);
529   gtk_widget_grab_focus(packet_list);
530
531   g_free(cf_name);
532 }
533
534 static void
535 file_open_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
536 {
537   /* Note that we no longer have a "Open Capture File" dialog box. */
538   file_open_w = NULL;
539 }
540
541 void file_close_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
542 {
543     switch(btn) {
544     case(ESD_BTN_YES):
545         /* save file first */
546         file_save_as_cmd(after_save_close_file, NULL);
547         break;
548     case(ESD_BTN_NO):
549         cf_close(&cfile);
550         break;
551     case(ESD_BTN_CANCEL):
552         break;
553     default:
554         g_assert_not_reached();
555     }
556 }
557
558 /* Close a file */
559 void
560 file_close_cmd_cb(GtkWidget *widget _U_, gpointer data _U_) {
561   gpointer  dialog;
562
563   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
564     /* user didn't saved his current file, ask him */
565     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
566                 PRIMARY_TEXT_START "Save capture file before closing it?" PRIMARY_TEXT_END "\n\n"
567                 "If you close without saving, your capture data will be discarded.");
568
569     simple_dialog_set_cb(dialog, file_close_answered_cb, NULL);
570   } else {
571     /* unchanged file, just close it */
572     cf_close(&cfile);
573   }
574 }
575
576 void
577 file_save_cmd_cb(GtkWidget *w, gpointer data) {
578   /* If the file's already been saved, do nothing.  */
579   if (cfile.user_saved)
580     return;
581
582   /* Do a "Save As". */
583   file_save_as_cmd_cb(w, data);
584 }
585
586 /* XXX - can we make these not be static? */
587 static packet_range_t range;
588 static gboolean color_marked;
589 static int filetype;
590 static GtkWidget *captured_bt;
591 static GtkWidget *displayed_bt;
592 static GtkWidget *select_all_rb;
593 static GtkWidget *select_all_c_lb;
594 static GtkWidget *select_all_d_lb;
595 static GtkWidget *select_curr_rb;
596 static GtkWidget *select_curr_c_lb;
597 static GtkWidget *select_curr_d_lb;
598 static GtkWidget *select_marked_only_rb;
599 static GtkWidget *select_marked_only_c_lb;
600 static GtkWidget *select_marked_only_d_lb;
601 static GtkWidget *select_marked_range_rb;
602 static GtkWidget *select_marked_range_c_lb;
603 static GtkWidget *select_marked_range_d_lb;
604 static GtkWidget *select_user_range_rb;
605 static GtkWidget *select_user_range_c_lb;
606 static GtkWidget *select_user_range_d_lb;
607 static GtkWidget *select_user_range_entry;
608 static GtkWidget *cfmark_cb;
609 static GtkWidget *ft_om;
610
611 static gboolean
612 can_save_with_wiretap(int ft)
613 {
614   /* To save a file with Wiretap, Wiretap has to handle that format,
615      and its code to handle that format must be able to write a file
616      with this file's encapsulation type. */
617   return wtap_dump_can_open(ft) && wtap_dump_can_write_encap(ft, cfile.lnk_t);
618 }
619
620 static void
621 file_set_save_dynamics(void) {
622   gboolean      filtered_active;
623   gchar         label_text[100];
624   gint          selected_num;
625
626
627   filtered_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(displayed_bt));
628
629   gtk_widget_set_sensitive(displayed_bt, can_save_with_wiretap(filetype));
630
631   gtk_widget_set_sensitive(select_all_c_lb, !filtered_active);
632   g_snprintf(label_text, sizeof(label_text), "%u", cfile.count);
633   gtk_label_set_text(GTK_LABEL(select_all_c_lb), label_text);
634   gtk_widget_set_sensitive(select_all_d_lb, filtered_active);
635   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_cnt);
636
637   gtk_label_set_text(GTK_LABEL(select_all_d_lb), label_text);
638
639   selected_num = (cfile.current_frame) ? cfile.current_frame->num : 0;
640   /* XXX: how to update the radio button label but keep the mnemonic? */
641 /*  g_snprintf(label_text, sizeof(label_text), "_Selected packet #%u only", selected_num);
642   gtk_label_set_text(GTK_LABEL(GTK_BIN(select_curr_rb)->child), label_text);*/
643   gtk_widget_set_sensitive(select_curr_rb, selected_num);
644   g_snprintf(label_text, sizeof(label_text), "%u", selected_num ? 1 : 0);
645   gtk_label_set_text(GTK_LABEL(select_curr_c_lb), label_text);
646   gtk_widget_set_sensitive(select_curr_c_lb, selected_num && !filtered_active);
647   g_snprintf(label_text, sizeof(label_text), "%u", selected_num ? 1 : 0);
648   gtk_label_set_text(GTK_LABEL(select_curr_d_lb), label_text);
649   gtk_widget_set_sensitive(select_curr_d_lb, selected_num && filtered_active);
650
651   gtk_widget_set_sensitive(select_marked_only_rb, cfile.marked_count);
652   g_snprintf(label_text, sizeof(label_text), "%u", cfile.marked_count);
653   gtk_label_set_text(GTK_LABEL(select_marked_only_c_lb), label_text);
654   gtk_widget_set_sensitive(select_marked_only_c_lb, cfile.marked_count && !filtered_active);
655   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_marked_cnt);
656   gtk_label_set_text(GTK_LABEL(select_marked_only_d_lb), label_text);
657   gtk_widget_set_sensitive(select_marked_only_d_lb, range.displayed_marked_cnt && filtered_active);
658
659   gtk_widget_set_sensitive(select_marked_range_rb, range.mark_range_cnt);
660   g_snprintf(label_text, sizeof(label_text), "%u", range.mark_range_cnt);
661   gtk_label_set_text(GTK_LABEL(select_marked_range_c_lb), label_text);
662   gtk_widget_set_sensitive(select_marked_range_c_lb, range.mark_range_cnt && !filtered_active);
663   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_mark_range_cnt);
664   gtk_label_set_text(GTK_LABEL(select_marked_range_d_lb), label_text);
665   gtk_widget_set_sensitive(select_marked_range_d_lb, range.displayed_mark_range_cnt && filtered_active);
666
667   gtk_widget_set_sensitive(select_user_range_rb, TRUE);
668   g_snprintf(label_text, sizeof(label_text), "%u", range.user_range_cnt);
669   gtk_label_set_text(GTK_LABEL(select_user_range_c_lb), label_text);
670   gtk_widget_set_sensitive(select_user_range_c_lb, !filtered_active);
671   g_snprintf(label_text, sizeof(label_text), "%u", range.displayed_user_range_cnt);
672   gtk_label_set_text(GTK_LABEL(select_user_range_d_lb), label_text);
673   gtk_widget_set_sensitive(select_user_range_d_lb, filtered_active);
674 }
675
676 /* Generate a list of the file types we can save this file as.
677
678    "filetype" is the type it has now.
679
680    "encap" is the encapsulation for its packets (which could be
681    "unknown" or "per-packet").
682
683    "filtered" is TRUE if we're to save only the packets that passed
684    the display filter (in which case we have to save it using Wiretap)
685    and FALSE if we're to save the entire file (in which case, if we're
686    saving it in the type it has already, we can just copy it).
687
688    The same applies for sel_curr, sel_all, sel_m_only, sel_m_range and sel_man_range
689 */
690 static void
691 set_file_type_list(GtkWidget *option_menu)
692 {
693   GtkWidget *ft_menu, *ft_menu_item;
694   int ft;
695   guint index;
696   guint item_to_select;
697
698   /* Default to the first supported file type, if the file's current
699      type isn't supported. */
700   item_to_select = 0;
701
702   ft_menu = gtk_menu_new();
703
704   /* Check all file types. */
705   index = 0;
706   for (ft = 0; ft < WTAP_NUM_FILE_TYPES; ft++) {
707     if (!packet_range_process_all(&range) || ft != cfile.cd_t) {
708       /* not all unfiltered packets or a different file type.  We have to use Wiretap. */
709       if (!can_save_with_wiretap(ft))
710         continue;       /* We can't. */
711     }
712
713     /* OK, we can write it out in this type. */
714     ft_menu_item = gtk_menu_item_new_with_label(wtap_file_type_string(ft));
715     if (ft == filetype) {
716       /* Default to the same format as the file, if it's supported. */
717       item_to_select = index;
718     }
719     SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
720                    GINT_TO_POINTER(ft));
721     gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
722     gtk_widget_show(ft_menu_item);
723     index++;
724   }
725
726   gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), ft_menu);
727   gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu), item_to_select);
728 }
729
730 static void
731 select_file_type_cb(GtkWidget *w _U_, gpointer data)
732 {
733   int new_filetype = GPOINTER_TO_INT(data);
734
735   if (filetype != new_filetype) {
736     /* We can select only the filtered or marked packets to be saved if we can
737        use Wiretap to save the file. */
738     gtk_widget_set_sensitive(displayed_bt, can_save_with_wiretap(new_filetype));
739     filetype = new_filetype;
740     file_set_save_marked_sensitive();
741   }
742 }
743
744 static void
745 toggle_captured_cb(GtkWidget *widget, gpointer data _U_)
746 {
747   /* is the button now active? */
748   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
749     /* They changed the state of the "captured" button. */
750     range.process_filtered = FALSE;
751     /* XXX: the following line fails, I have no idea why */
752     /* set_file_type_list(ft_om);*/
753
754     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(captured_bt), TRUE);
755     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(displayed_bt), FALSE);
756
757     file_set_save_dynamics();
758   }
759 }
760
761 static void
762 toggle_filtered_cb(GtkWidget *widget, gpointer data _U_)
763 {
764   /* is the button now active? */
765   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
766     range.process_filtered = TRUE;
767     set_file_type_list(ft_om);
768
769     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(captured_bt), FALSE);
770     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(displayed_bt), TRUE);
771     
772     file_set_save_dynamics();
773   }
774 }
775
776 static void
777 toggle_select_all(GtkWidget *widget, gpointer data _U_)
778 {
779   /* is the button now active? */
780   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
781     range.process = range_process_all;
782     set_file_type_list(ft_om);
783     file_set_save_dynamics();
784   }
785 }
786
787 static void
788 toggle_select_selected(GtkWidget *widget, gpointer data _U_)
789 {
790   /* is the button now active? */
791   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
792     range.process = range_process_selected;
793     set_file_type_list(ft_om);
794     file_set_save_dynamics();
795   }
796 }
797
798 static void
799 toggle_select_marked_only(GtkWidget *widget, gpointer data _U_)
800 {
801   /* is the button now active? */
802   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
803     range.process = range_process_marked;
804     set_file_type_list(ft_om);
805     file_set_save_dynamics();
806   }
807 }
808
809 static void
810 toggle_select_marked_range(GtkWidget *widget, gpointer data _U_)
811 {
812   /* is the button now active? */
813   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
814     range.process = range_process_marked_range;
815     set_file_type_list(ft_om);
816     file_set_save_dynamics();
817   }
818 }
819
820 static void
821 toggle_select_user_range(GtkWidget *widget, gpointer data _U_)
822 {
823   /* is the button now active? */
824   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget))) {
825     range.process = range_process_user_range;
826     set_file_type_list(ft_om);
827     file_set_save_dynamics();
828   }
829         
830   /* Make the entry widget sensitive or insensitive */
831   gtk_widget_set_sensitive(select_user_range_entry, range.process == range_process_user_range);
832
833   /* When selecting user specified range, then focus on the entry */
834   if (range.process == range_process_user_range)
835       gtk_widget_grab_focus(select_user_range_entry);
836
837 }
838
839 static void
840 range_entry(GtkWidget *entry)
841 {
842   const gchar *entry_text;
843
844   entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
845   packet_range_convert_str(&range, entry_text);
846   file_set_save_dynamics();
847 }
848
849 /*
850  * Set the "Save only marked packets" toggle button as appropriate for
851  * the current output file type and count of marked packets.
852  *
853  * Called when the "Save As..." dialog box is created and when either
854  * the file type or the marked count changes.
855  */
856 void
857 file_set_save_marked_sensitive(void)
858 {
859   if (file_save_as_w == NULL) {
860     /* We don't currently have a "Save As..." dialog box up. */
861     return;
862   }
863         
864   /* We can request that only the marked packets be saved only if we
865      can use Wiretap to save the file and if there *are* marked packets. */
866   if (can_save_with_wiretap(filetype) && cfile.marked_count != 0) {
867     gtk_widget_set_sensitive(select_marked_only_rb, TRUE);
868     gtk_widget_set_sensitive(select_marked_range_rb, TRUE);       
869   }
870   else {
871     /* Force the "Save only marked packets" toggle to "false", turn
872        off the flag it controls, and update the list of types we can
873        save the file as. */
874     range.process = range_process_all;
875     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_marked_only_rb), FALSE);
876     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_marked_range_rb), FALSE);       
877     set_file_type_list(ft_om);
878     gtk_widget_set_sensitive(select_marked_only_rb,  FALSE);
879     gtk_widget_set_sensitive(select_marked_range_rb, FALSE);      
880   }
881 }
882
883 action_after_save_e action_after_save_g;
884 gpointer            action_after_save_data_g;
885
886
887 void
888 file_save_as_cmd(action_after_save_e action_after_save, gpointer action_after_save_data)
889 {
890   GtkWidget     *main_vb, *ft_hb, *ft_lb, *range_fr, *range_tb;
891   GtkTooltips   *tooltips;
892
893 #if GTK_MAJOR_VERSION < 2
894   GtkAccelGroup *accel_group;
895 #endif
896           
897   if (file_save_as_w != NULL) {
898     /* There's already an "Save Capture File As" dialog box; reactivate it. */
899     reactivate_window(file_save_as_w);
900     return;
901   }
902
903   /* Default to saving all packets, in the file's current format. */
904   filetype = cfile.cd_t;
905
906   /* init the packet range */
907   packet_range_init(&range);
908
909   /* Enable tooltips */
910   tooltips = gtk_tooltips_new();
911           
912   /* build the file selection */
913 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
914   file_save_as_w = file_selection_new ("Ethereal: Save Capture File As",
915                                        GTK_FILE_CHOOSER_ACTION_SAVE);
916 #else
917   file_save_as_w = file_selection_new ("Ethereal: Save Capture File As");
918 #endif
919   SIGNAL_CONNECT(file_save_as_w, "destroy", file_save_as_destroy_cb, NULL);
920
921   /* as the dialog might already be gone, when using this values, we cannot
922    * set data to the dialog object, but keep global values */
923   action_after_save_g       = action_after_save;
924   action_after_save_data_g  = action_after_save_data;
925
926 #if GTK_MAJOR_VERSION < 2
927   accel_group = gtk_accel_group_new();
928   gtk_window_add_accel_group(GTK_WINDOW(file_save_as_w), accel_group);
929 #endif
930         
931   /* If we've opened a file, start out by showing the files in the directory
932      in which that file resided. */
933 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
934   if (last_open_dir)
935     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_save_as_w),
936                                         last_open_dir);
937 #else
938   if (last_open_dir)
939     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w),
940                                     last_open_dir);
941 #endif
942
943   /* Container for each row of widgets */
944        
945   main_vb = gtk_vbox_new(FALSE, 5);
946   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
947 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
948   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_save_as_w), main_vb);
949 #else
950   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_save_as_w)->action_area),
951                      main_vb, FALSE, FALSE, 0);
952 #endif
953   gtk_widget_show(main_vb);     
954                 
955   /*** Packet Range frame ***/
956   range_fr = gtk_frame_new("Packet Range");
957   gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 0);
958   gtk_widget_show(range_fr);
959   
960   /* range table */
961   range_tb = gtk_table_new(7, 3, FALSE);
962   gtk_container_border_width(GTK_CONTAINER(range_tb), 5);
963   gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
964   gtk_widget_show(range_tb);
965
966   /* captured button */
967   captured_bt = TOGGLE_BUTTON_NEW_WITH_MNEMONIC("_Captured", accel_group);
968   gtk_table_attach_defaults(GTK_TABLE(range_tb), captured_bt, 1, 2, 0, 1);
969   SIGNAL_CONNECT(captured_bt, "toggled", toggle_captured_cb, NULL);
970   gtk_tooltips_set_tip (tooltips,captured_bt,("Process all the below chosen packets"), NULL);
971   gtk_widget_show(captured_bt);
972
973   /* displayed button */
974   displayed_bt = TOGGLE_BUTTON_NEW_WITH_MNEMONIC("_Displayed", accel_group);
975   gtk_table_attach_defaults(GTK_TABLE(range_tb), displayed_bt, 2, 3, 0, 1);
976   SIGNAL_CONNECT(displayed_bt, "toggled", toggle_filtered_cb, NULL);
977   gtk_tooltips_set_tip (tooltips,displayed_bt,("Process only the below chosen packets, which also passes the current display filter"), NULL);
978   gtk_widget_show(displayed_bt);
979
980
981   /* Process all packets */
982   select_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "_All packets", accel_group);
983   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_all_rb, 0, 1, 1, 2);
984   gtk_tooltips_set_tip (tooltips,select_all_rb,("Process all packets"), NULL);
985   SIGNAL_CONNECT(select_all_rb, "toggled", toggle_select_all, NULL);
986   gtk_widget_show(select_all_rb);
987
988   select_all_c_lb = gtk_label_new("?");
989   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_all_c_lb, 1, 2, 1, 2);
990   gtk_widget_show(select_all_c_lb);
991   select_all_d_lb = gtk_label_new("?");
992   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_all_d_lb, 2, 3, 1, 2);
993   gtk_widget_show(select_all_d_lb);
994
995         
996   /* Process currently selected */
997   select_curr_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "_Selected packet only", accel_group);
998   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_curr_rb, 0, 1, 2, 3);
999   gtk_tooltips_set_tip (tooltips,select_curr_rb,("Process the currently selected packet only"), NULL);
1000   SIGNAL_CONNECT(select_curr_rb, "toggled", toggle_select_selected, NULL);
1001   gtk_widget_show(select_curr_rb);
1002         
1003   select_curr_c_lb = gtk_label_new("?");
1004   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_curr_c_lb, 1, 2, 2, 3);
1005   gtk_widget_show(select_curr_c_lb);
1006   select_curr_d_lb = gtk_label_new("?");
1007   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_curr_d_lb, 2, 3, 2, 3);
1008   gtk_widget_show(select_curr_d_lb);
1009
1010
1011   /* Process marked packets */
1012   select_marked_only_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "_Marked packets only", accel_group);
1013   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_only_rb, 0, 1, 3, 4);
1014   gtk_tooltips_set_tip (tooltips,select_marked_only_rb,("Process marked packets only"), NULL);
1015   SIGNAL_CONNECT(select_marked_only_rb, "toggled", toggle_select_marked_only, NULL);
1016   gtk_widget_show(select_marked_only_rb);
1017
1018   select_marked_only_c_lb = gtk_label_new("?");
1019   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_only_c_lb, 1, 2, 3, 4);
1020   gtk_widget_show(select_marked_only_c_lb);
1021   select_marked_only_d_lb = gtk_label_new("?");
1022   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_only_d_lb, 2, 3, 3, 4);
1023   gtk_widget_show(select_marked_only_d_lb);
1024
1025   
1026   /* Process packet range between first and last packet */
1027   select_marked_range_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "From first _to last marked packet", accel_group);
1028   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_range_rb, 0, 1, 4, 5);
1029   gtk_tooltips_set_tip (tooltips,select_marked_range_rb,("Process all packets between the first and last marker"), NULL);
1030   SIGNAL_CONNECT(select_marked_range_rb, "toggled", toggle_select_marked_range, NULL);
1031   gtk_widget_show(select_marked_range_rb);
1032
1033   select_marked_range_c_lb = gtk_label_new("?");
1034   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_range_c_lb, 1, 2, 4, 5);
1035   gtk_widget_show(select_marked_range_c_lb);
1036   select_marked_range_d_lb = gtk_label_new("?");
1037   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_marked_range_d_lb, 2, 3, 4, 5);
1038   gtk_widget_show(select_marked_range_d_lb);
1039
1040
1041   /* Process a user specified provided packet range : -10,30,40-70,80- */
1042   select_user_range_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(select_all_rb, "Specify a packet _range:", accel_group);
1043   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_rb, 0, 1, 5, 6);
1044   gtk_tooltips_set_tip (tooltips,select_user_range_rb,("Process a specified packet range"), NULL);
1045   SIGNAL_CONNECT(select_user_range_rb, "toggled", toggle_select_user_range, NULL);
1046   gtk_widget_show(select_user_range_rb);
1047
1048   select_user_range_c_lb = gtk_label_new("?");
1049   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_c_lb, 1, 2, 5, 6);
1050   gtk_widget_show(select_user_range_c_lb);
1051   select_user_range_d_lb = gtk_label_new("?");
1052   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_d_lb, 2, 3, 5, 6);
1053   gtk_widget_show(select_user_range_d_lb);
1054
1055
1056   /* The entry part */
1057   select_user_range_entry = gtk_entry_new();
1058   gtk_entry_set_max_length (GTK_ENTRY (select_user_range_entry), 254);
1059   gtk_table_attach_defaults(GTK_TABLE(range_tb), select_user_range_entry, 0, 1, 6, 7);
1060   gtk_tooltips_set_tip (tooltips,select_user_range_entry, 
1061         ("Specify a range of packet numbers :     \nExample :  1-10,18,25-100,332-"), NULL);
1062   SIGNAL_CONNECT(select_user_range_entry,"changed", range_entry, select_user_range_entry);      
1063   gtk_widget_set_sensitive(select_user_range_entry, FALSE);
1064   gtk_widget_show(select_user_range_entry);
1065
1066   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(captured_bt), TRUE);
1067   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(displayed_bt), FALSE);
1068   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_all_rb),  TRUE);
1069   
1070   /* File type row */
1071   ft_hb = gtk_hbox_new(FALSE, 3);
1072   gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
1073   gtk_widget_show(ft_hb);
1074
1075   ft_lb = gtk_label_new("File type:");
1076   gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
1077   gtk_widget_show(ft_lb);
1078
1079   ft_om = gtk_option_menu_new();
1080
1081   /* Generate the list of file types we can save. */
1082   set_file_type_list(ft_om);
1083   gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
1084   gtk_widget_show(ft_om);
1085
1086   /*
1087    * Set the sensitivity of the "Save only marked packets" toggle
1088    * button
1089    *
1090    * This has to be done after we create the file type menu option,
1091    * as the routine that sets it also sets that menu.
1092    */
1093   file_set_save_marked_sensitive();
1094         
1095   /* dynamic values in the range frame */
1096   file_set_save_dynamics();
1097
1098 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1099   if (gtk_dialog_run(GTK_DIALOG(file_save_as_w)) == GTK_RESPONSE_ACCEPT)
1100   {
1101     file_save_as_ok_cb(file_save_as_w, file_save_as_w);
1102   }
1103   else gtk_widget_destroy(file_save_as_w);
1104 #else
1105   /* Connect the ok_button to file_save_as_ok_cb function and pass along a
1106      pointer to the file selection box widget */
1107   SIGNAL_CONNECT(GTK_FILE_SELECTION (file_save_as_w)->ok_button, "clicked",
1108                  file_save_as_ok_cb, file_save_as_w);
1109
1110   /* Connect the cancel_button to destroy the widget */
1111   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_save_as_w)->cancel_button,
1112                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
1113                         file_save_as_w);
1114
1115   /* Catch the "key_press_event" signal in the window, so that we can catch
1116      the ESC key being pressed and act as if the "Cancel" button had
1117      been selected. */
1118   dlg_set_cancel(file_save_as_w, GTK_FILE_SELECTION(file_save_as_w)->cancel_button);
1119
1120   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_save_as_w), "");
1121
1122   gtk_widget_show(file_save_as_w);
1123 #endif
1124 }
1125
1126 void
1127 file_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1128 {
1129   file_save_as_cmd(after_save_no_action, NULL);
1130 }
1131
1132 static void
1133 file_save_as_ok_cb(GtkWidget *w _U_, gpointer fs) {
1134   gchar *cf_name;
1135   gchar *dirname;
1136
1137 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1138   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1139 #else
1140   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1141 #endif
1142
1143   /* Perhaps the user specified a directory instead of a file.
1144      Check whether they did. */
1145   if (test_for_directory(cf_name) == EISDIR) {
1146         /* It's a directory - set the file selection box to display that
1147            directory, and leave the selection box displayed. */
1148         set_last_open_dir(cf_name);
1149         g_free(cf_name);
1150         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1151         return;
1152   }
1153
1154   /* don't show the dialog while saving */
1155   gtk_widget_hide(GTK_WIDGET (fs));
1156
1157   /* Write out the packets (all, or only the ones from the current
1158      range) to the file with the specified name. */
1159   if (! cf_save(cf_name, &cfile, &range, filetype)) {
1160     /* The write failed; don't dismiss the open dialog box,
1161        just leave it around so that the user can, after they
1162        dismiss the alert box popped up for the error, try again. */
1163     g_free(cf_name);
1164     gtk_widget_show(GTK_WIDGET (fs));
1165     return;
1166   }
1167
1168   /* The write succeeded; get rid of the file selection box. */
1169   /* cf_save might already closed our dialog! */
1170   if (file_save_as_w)
1171     gtk_widget_destroy(GTK_WIDGET (fs));
1172
1173   /* Save the directory name for future file dialogs. */
1174   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
1175   set_last_open_dir(dirname);
1176   g_free(cf_name);
1177
1178   /* we have finished saving, do we have pending things to do? */
1179   switch(action_after_save_g) {
1180   case(after_save_no_action):
1181       break;
1182   case(after_save_open_dialog):
1183       file_open_cmd(action_after_save_data_g);
1184       break;
1185   case(after_save_open_recent_file):
1186       menu_open_recent_file_cmd(action_after_save_data_g);
1187       break;
1188   case(after_save_open_dnd_file):
1189       dnd_open_file_cmd(action_after_save_data_g);
1190       break;
1191 #ifdef HAVE_LIBPCAP
1192   case(after_save_capture_dialog):
1193       capture_prep();
1194       break;
1195 #endif
1196   case(after_save_close_file):
1197       cf_close(&cfile);
1198       break;
1199   case(after_save_exit):
1200       main_do_quit();
1201       break;
1202   default:
1203       g_assert_not_reached();
1204   }
1205
1206   action_after_save_g = after_save_no_action;
1207 }
1208
1209 void
1210 file_save_as_destroy(void)
1211 {
1212   if (file_save_as_w)
1213     gtk_widget_destroy(file_save_as_w);
1214 }
1215
1216 static void
1217 file_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1218 {
1219   /* Note that we no longer have a "Save Capture File As" dialog box. */
1220   file_save_as_w = NULL;
1221 }
1222
1223 /* Reload a file using the current read and display filters */
1224 void
1225 file_reload_cmd_cb(GtkWidget *w _U_, gpointer data _U_) {
1226   gchar *filename;
1227   gboolean is_tempfile;
1228
1229   /* If the file could be opened, "cf_open()" calls "cf_close()"
1230      to get rid of state for the old capture file before filling in state
1231      for the new capture file.  "cf_close()" will remove the file if
1232      it's a temporary file; we don't want that to happen (for one thing,
1233      it'd prevent subsequent reopens from working).  Remember whether it's
1234      a temporary file, mark it as not being a temporary file, and then
1235      reopen it as the type of file it was.
1236
1237      Also, "cf_close()" will free "cfile.filename", so we must make
1238      a copy of it first. */
1239   filename = g_strdup(cfile.filename);
1240   is_tempfile = cfile.is_tempfile;
1241   cfile.is_tempfile = FALSE;
1242   if (cf_open(filename, is_tempfile, &cfile) == 0) {
1243     switch (cf_read(&cfile)) {
1244
1245     case READ_SUCCESS:
1246     case READ_ERROR:
1247       /* Just because we got an error, that doesn't mean we were unable
1248          to read any of the file; we handle what we could get from the
1249          file. */
1250       break;
1251
1252     case READ_ABORTED:
1253       /* The user bailed out of re-reading the capture file; the
1254          capture file has been closed - just free the capture file name
1255          string and return (without changing the last containing
1256          directory). */
1257       g_free(filename);
1258       return;
1259     }
1260   } else {
1261     /* The open failed, so "cfile.is_tempfile" wasn't set to "is_tempfile".
1262        Instead, the file was left open, so we should restore "cfile.is_tempfile"
1263        ourselves.
1264
1265        XXX - change the menu?  Presumably "cf_open()" will do that;
1266        make sure it does! */
1267     cfile.is_tempfile = is_tempfile;
1268   }
1269   /* "cf_open()" made a copy of the file name we handed it, so
1270      we should free up our copy. */
1271   g_free(filename);
1272 }
1273
1274 /******************** Color Filters *********************************/
1275 /*
1276  * Keep a static pointer to the current "Color Export" window, if
1277  * any, so that if somebody tries to do "Export"
1278  * while there's already a "Color Export" window up, we just pop
1279  * up the existing one, rather than creating a new one.
1280  */
1281 static GtkWidget *file_color_import_w;
1282
1283 /* sets the file path to the global color filter file.
1284    WARNING: called by both the import and the export dialog.
1285 */
1286 static void
1287 color_global_cb(GtkWidget *widget _U_, gpointer data)
1288 {
1289   GtkWidget *fs_widget = data;
1290   gchar *path;
1291
1292   /* decide what file to open (from dfilter code) */
1293   path = get_datafile_path("colorfilters");
1294
1295 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1296   gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(fs_widget), path);
1297 #else
1298   gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs_widget), path);
1299 #endif
1300   g_free((gchar *)path);
1301 }
1302
1303 /* Import color filters */
1304 void
1305 file_color_import_cmd_cb(GtkWidget *w _U_, gpointer data)
1306 {
1307   GtkWidget     *main_vb, *cfglobal_but;
1308 #if GTK_MAJOR_VERSION < 2
1309   GtkAccelGroup *accel_group;
1310 #endif
1311   /* No Apply button, and "OK" just sets our text widget, it doesn't
1312      activate it (i.e., it doesn't cause us to try to open the file). */
1313
1314   if (file_color_import_w != NULL) {
1315     /* There's already an "Import Color Filters" dialog box; reactivate it. */
1316     reactivate_window(file_color_import_w);
1317     return;
1318   }
1319
1320 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1321   file_color_import_w = file_selection_new("Ethereal: Import Color Filters",
1322                                            GTK_FILE_CHOOSER_ACTION_OPEN);
1323 #else
1324   file_color_import_w = gtk_file_selection_new("Ethereal: Import Color Filters");
1325 #endif
1326   SIGNAL_CONNECT(file_color_import_w, "destroy", file_color_import_destroy_cb, NULL);
1327
1328 #if GTK_MAJOR_VERSION < 2
1329   /* Accelerator group for the accelerators (or, as they're called in
1330      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
1331      Ctrl+<key> is an accelerator). */
1332   accel_group = gtk_accel_group_new();
1333   gtk_window_add_accel_group(GTK_WINDOW(file_color_import_w), accel_group);
1334 #endif
1335
1336   /* If we've opened a file, start out by showing the files in the directory
1337      in which that file resided. */
1338 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1339   if (last_open_dir)
1340     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_color_import_w),
1341                                         last_open_dir);
1342 #else
1343   if (last_open_dir)
1344     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_import_w),
1345                                     last_open_dir);
1346 #endif
1347
1348   /* Container for each row of widgets */
1349   main_vb = gtk_vbox_new(FALSE, 3);
1350   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1351 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1352   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_color_import_w),
1353                                     main_vb);
1354 #else
1355   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_import_w)->action_area),
1356                      main_vb, FALSE, FALSE, 0);
1357 #endif
1358   gtk_widget_show(main_vb);
1359
1360
1361   cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1362   gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1363   SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_import_w);
1364   gtk_widget_show(cfglobal_but);
1365
1366 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1367   OBJECT_SET_DATA(file_color_import_w, ARGUMENT_CL, data);
1368
1369   if (gtk_dialog_run(GTK_DIALOG(file_color_import_w)) == GTK_RESPONSE_ACCEPT)
1370   {
1371       file_color_import_ok_cb(file_color_import_w, file_color_import_w);
1372   }
1373   else gtk_widget_destroy(file_color_import_w);
1374 #else
1375   /* Connect the ok_button to file_open_ok_cb function and pass along a
1376      pointer to the file selection box widget */
1377   SIGNAL_CONNECT(GTK_FILE_SELECTION(file_color_import_w)->ok_button, "clicked",
1378                  file_color_import_ok_cb, file_color_import_w);
1379
1380   OBJECT_SET_DATA(GTK_FILE_SELECTION(file_color_import_w)->ok_button,
1381                   ARGUMENT_CL, data);
1382
1383   /* Connect the cancel_button to destroy the widget */
1384   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_import_w)->cancel_button,
1385                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
1386                         file_color_import_w);
1387
1388   /* Catch the "key_press_event" signal in the window, so that we can catch
1389      the ESC key being pressed and act as if the "Cancel" button had
1390      been selected. */
1391   dlg_set_cancel(file_color_import_w, GTK_FILE_SELECTION(file_color_import_w)->cancel_button);
1392
1393   gtk_widget_show(file_color_import_w);
1394 #endif
1395 }
1396
1397 static void
1398 file_color_import_ok_cb(GtkWidget *w, gpointer fs) {
1399   gchar     *cf_name, *s;
1400   gpointer  argument;
1401
1402   argument = OBJECT_GET_DATA(w, ARGUMENT_CL);     /* to be passed back into read_other_filters */
1403   
1404 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1405   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1406 #else
1407   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1408 #endif
1409   /* Perhaps the user specified a directory instead of a file.
1410      Check whether they did. */
1411   if (test_for_directory(cf_name) == EISDIR) {
1412         /* It's a directory - set the file selection box to display that
1413            directory, don't try to open the directory as a capture file. */
1414         set_last_open_dir(cf_name);
1415         g_free(cf_name);
1416         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1417         return;
1418   }
1419
1420   /* Try to open the capture file. */
1421
1422   if (!read_other_filters(cf_name, argument)) {
1423     /* We couldn't open it; don't dismiss the open dialog box,
1424        just leave it around so that the user can, after they
1425        dismiss the alert box popped up for the open error,
1426        try again. */
1427     g_free(cf_name);
1428     return;
1429   }
1430
1431   /* We've crossed the Rubicon; get rid of the file selection box. */
1432   gtk_widget_hide(GTK_WIDGET (fs));
1433   gtk_widget_destroy(GTK_WIDGET (fs));
1434
1435   /* Save the name of the containing directory specified in the path name,
1436      if any; we can write over cf_name, which is a good thing, given that
1437      "get_dirname()" does write over its argument. */
1438   s = get_dirname(cf_name);
1439   set_last_open_dir(s);
1440   gtk_widget_grab_focus(packet_list);
1441
1442   g_free(cf_name);
1443 }
1444
1445 static void
1446 file_color_import_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1447 {
1448   /* Note that we no longer have a "Open Capture File" dialog box. */
1449   file_color_import_w = NULL;
1450 }
1451
1452 static GtkWidget *file_color_export_w;
1453 /*
1454  * Set the "Export only marked filters" toggle button as appropriate for
1455  * the current output file type and count of marked filters.
1456  *
1457  * Called when the "Export" dialog box is created and when the marked
1458  * count changes.
1459  */
1460 void
1461 color_set_export_marked_sensitive(GtkWidget * cfmark_cb)
1462 {
1463   if (file_color_export_w == NULL) {
1464     /* We don't currently have an "Export" dialog box up. */
1465     return;
1466   }
1467
1468   /* We can request that only the marked filters be saved only if
1469         there *are* marked filters. */
1470   if (color_marked_count() != 0)
1471     gtk_widget_set_sensitive(cfmark_cb, TRUE);
1472   else {
1473     /* Force the "Export only marked filters" toggle to "false", turn
1474        off the flag it controls. */
1475     color_marked = FALSE;
1476     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1477     gtk_widget_set_sensitive(cfmark_cb, FALSE);
1478   }
1479 }
1480
1481 static void
1482 color_toggle_marked_cb(GtkWidget *widget, gpointer data _U_)
1483 {
1484   color_marked = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
1485 }
1486
1487 void
1488 file_color_export_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
1489 {
1490   GtkWidget *main_vb, *cfglobal_but;
1491
1492   if (file_color_export_w != NULL) {
1493     /* There's already an "Color Filter Export" dialog box; reactivate it. */
1494     reactivate_window(file_color_export_w);
1495     return;
1496   }
1497
1498   /* Default to saving all packets, in the file's current format. */
1499   color_marked   = FALSE;
1500   filetype = cfile.cd_t;
1501
1502 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1503   file_color_export_w = file_selection_new("Ethereal: Export Color Filters",
1504                                            GTK_FILE_CHOOSER_ACTION_SAVE);
1505 #else
1506   file_color_export_w = gtk_file_selection_new("Ethereal: Export Color Filters");
1507 #endif
1508   SIGNAL_CONNECT(file_color_export_w, "destroy", file_color_export_destroy_cb, NULL);
1509
1510   /* If we've opened a file, start out by showing the files in the directory
1511      in which that file resided. */
1512 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1513   if (last_open_dir)
1514     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_color_export_w),
1515                                         last_open_dir);
1516 #else
1517   if (last_open_dir)
1518     gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w),
1519                                     last_open_dir);
1520
1521 #endif
1522   /* Container for each row of widgets */
1523   main_vb = gtk_vbox_new(FALSE, 3);
1524   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1525 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1526   gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_color_export_w),
1527                                     main_vb);
1528 #else
1529   gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_export_w)->action_area),
1530     main_vb, FALSE, FALSE, 0);
1531 #endif
1532   gtk_widget_show(main_vb);
1533
1534   cfmark_cb = gtk_check_button_new_with_label("Export only marked filters");
1535   gtk_container_add(GTK_CONTAINER(main_vb), cfmark_cb);
1536   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cfmark_cb), FALSE);
1537   SIGNAL_CONNECT(cfmark_cb, "toggled", color_toggle_marked_cb, NULL);
1538   gtk_widget_show(cfmark_cb);
1539   color_set_export_marked_sensitive(cfmark_cb);
1540
1541   cfglobal_but = gtk_button_new_with_label("Global Color Filter File");
1542   gtk_container_add(GTK_CONTAINER(main_vb), cfglobal_but);
1543   SIGNAL_CONNECT(cfglobal_but, "clicked", color_global_cb, file_color_export_w);
1544   gtk_widget_show(cfglobal_but);
1545
1546 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1547   if (gtk_dialog_run(GTK_DIALOG(file_color_export_w)) == GTK_RESPONSE_ACCEPT)
1548   {
1549       file_color_export_ok_cb(file_color_export_w, file_color_export_w);
1550   }
1551   else gtk_widget_destroy(file_color_export_w);
1552 #else
1553   /* Connect the ok_button to file_export_ok_cb function and pass along a
1554      pointer to the file selection box widget */
1555   SIGNAL_CONNECT(GTK_FILE_SELECTION (file_color_export_w)->ok_button, "clicked",
1556                  file_color_export_ok_cb, file_color_export_w);
1557
1558   /* Connect the cancel_button to destroy the widget */
1559   SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_export_w)->cancel_button,
1560                         "clicked", (GtkSignalFunc)gtk_widget_destroy,
1561                         file_color_export_w);
1562
1563   /* Catch the "key_press_event" signal in the window, so that we can catch
1564      the ESC key being pressed and act as if the "Cancel" button had
1565      been selected. */
1566   dlg_set_cancel(file_color_export_w, GTK_FILE_SELECTION(file_color_export_w)->cancel_button);
1567
1568   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_export_w), "");
1569
1570   gtk_widget_show(file_color_export_w);
1571 #endif
1572 }
1573
1574 static void
1575 file_color_export_ok_cb(GtkWidget *w _U_, gpointer fs) {
1576   gchar *cf_name;
1577   gchar *dirname;
1578
1579 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 4) || GTK_MAJOR_VERSION > 2
1580   cf_name = g_strdup(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)));
1581 #else
1582   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
1583 #endif
1584
1585   /* Perhaps the user specified a directory instead of a file.
1586      Check whether they did. */
1587   if (test_for_directory(cf_name) == EISDIR) {
1588         /* It's a directory - set the file selection box to display that
1589            directory, and leave the selection box displayed. */
1590         set_last_open_dir(cf_name);
1591         g_free(cf_name);
1592         gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1593         return;
1594   }
1595
1596   /* Write out the filters (all, or only the ones that are currently
1597      displayed or marked) to the file with the specified name. */
1598
1599    if (!write_other_filters(cf_name, color_marked))
1600    {
1601     /* The write failed; don't dismiss the open dialog box,
1602        just leave it around so that the user can, after they
1603        dismiss the alert box popped up for the error, try again. */
1604
1605        g_free(cf_name);
1606        return;
1607    }
1608
1609   /* The write succeeded; get rid of the file selection box. */
1610   gtk_widget_hide(GTK_WIDGET (fs));
1611   gtk_widget_destroy(GTK_WIDGET (fs));
1612
1613   /* Save the directory name for future file dialogs. */
1614   dirname = get_dirname(cf_name);  /* Overwrites cf_name */
1615   set_last_open_dir(dirname);
1616   g_free(cf_name);
1617 }
1618
1619 static void
1620 file_color_export_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
1621 {
1622   file_color_export_w = NULL;
1623 }