put all required data into the print_args,
[obnox/wireshark/wip.git] / gtk / print_dlg.c
1 /* print_dlg.c
2  * Dialog boxes for printing
3  *
4  * $Id: print_dlg.c,v 1.73 2004/04/25 12:04:08 ulfl 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 <string.h>
30
31 #include <gtk/gtk.h>
32
33 #include "globals.h"
34 #include "keys.h"
35 #include "print.h"
36 #include "prefs.h"
37 #include "alert_box.h"
38 #include "simple_dialog.h"
39 #include "file_dlg.h"
40 #include "ui_util.h"
41 #include "dlg_utils.h"
42 #include "main.h"
43 #include <epan/epan_dissect.h>
44 #include <epan/filesystem.h>
45 #ifdef _WIN32
46 #include <io.h>
47 #include "print_mswin.h"
48 #endif
49 #include "compat_macros.h"
50 #include "range_utils.h"
51
52
53 /* On Win32, a GUI application apparently can't use "popen()" (it
54   "returns an invalid file handle, if used in a Windows program,
55   that will cause the program to hang indefinitely"), so we can't
56   use a pipe to a print command to print to a printer.
57
58   Eventually, we should try to use the native Win32 printing API
59   for this (and also use various UNIX printing APIs, when present?).
60 */
61
62 static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data);
63 static void print_cmd_toggle_detail(GtkWidget *widget, gpointer data);
64 static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
65 static void print_close_cb(GtkWidget *close_bt, gpointer parent_w);
66 static void print_destroy_cb(GtkWidget *win, gpointer user_data);
67
68
69
70 #define PRINT_ARGS_KEY            "printer_args"
71
72 #define PRINT_PS_RB_KEY           "printer_ps_radio_button"
73 #define PRINT_PDML_RB_KEY         "printer_pdml_radio_button"
74 #define PRINT_PSML_RB_KEY         "printer_psml_radio_button"
75 #define PRINT_DEST_CB_KEY         "printer_destination_check_button"
76
77 #define PRINT_SUMMARY_CB_KEY      "printer_summary_check_button"
78 #define PRINT_DETAILS_CB_KEY      "printer_details_check_button"
79 #define PRINT_COLLAPSE_ALL_RB_KEY "printer_collapse_all_radio_button"
80 #define PRINT_AS_DISPLAYED_RB_KEY "printer_as_displayed_radio_button"
81 #define PRINT_EXPAND_ALL_RB_KEY   "printer_expand_all_radio_button"
82 #define PRINT_HEX_CB_KEY          "printer_hex_check_button"
83 #define PRINT_FORMFEED_CB_KEY     "printer_formfeed_check_button"
84
85 #define PRINT_BT_KEY              "printer_button"
86
87 /*
88  * Keep a static pointer to the current "Print" window, if any, so that if
89  * somebody tries to do "File:Print" while there's already a "Print" window
90  * up, we just pop up the existing one, rather than creating a new one.
91  */
92 static GtkWidget *print_w = NULL;
93
94 static print_args_t  print_args;
95
96 static gboolean print_prefs_init = FALSE;
97
98
99 /* Open the print dialog */
100 void
101 file_print_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
102 {
103 #if GTK_MAJOR_VERSION < 2
104   GtkAccelGroup *accel_group;
105 #endif
106
107   GtkWidget     *main_vb;
108
109   GtkWidget     *printer_fr, *printer_vb;
110   GtkWidget     *text_rb, *ps_rb, *pdml_rb, *psml_rb;
111   GtkWidget     *printer_tb, *dest_cb;
112 #ifndef _WIN32
113   GtkWidget     *cmd_lb, *cmd_te;
114 #endif
115   GtkWidget     *file_bt, *file_te;
116
117   GtkWidget     *range_fr, *range_tb;
118
119   GtkWidget     *packet_hb;
120
121   GtkWidget     *format_fr, *format_vb;
122   GtkWidget     *summary_cb;
123
124   GtkWidget     *details_cb;
125   GtkWidget     *details_hb, *details_vb;
126   GtkWidget     *collapse_all_rb, *as_displayed_rb, *expand_all_rb;
127   GtkWidget     *hex_cb;
128   GtkWidget     *sep, *formfeed_cb;
129
130   GtkWidget     *bbox, *ok_bt, *cancel_bt;
131
132   GtkTooltips   *tooltips;
133
134   print_args_t  *args = &print_args;
135
136   if (print_w != NULL) {
137     /* There's already a "Print" dialog box; reactivate it. */
138     reactivate_window(print_w);
139     return;
140   }
141
142   /* get settings from preferences (and other initial values) only once */
143   if(print_prefs_init == FALSE) {
144       print_prefs_init          = TRUE;
145       args->format              = prefs.pr_format;
146       args->to_file             = prefs.pr_dest;
147       args->file                = g_strdup(prefs.pr_file);
148       args->cmd                 = g_strdup(prefs.pr_cmd);
149       args->print_summary       = TRUE;
150       args->print_dissections   = print_dissections_as_displayed;
151       args->print_hex           = FALSE;
152       args->print_formfeed      = FALSE;
153   
154       /* init the printing range */
155       packet_range_init(&args->range);
156   }
157
158   /* Enable tooltips */
159   tooltips = gtk_tooltips_new();
160
161   /* dialog window */
162   print_w = dlg_window_new("Ethereal: Print");
163   SIGNAL_CONNECT(print_w, "destroy", print_destroy_cb, NULL);
164
165 #if GTK_MAJOR_VERSION < 2
166   /* Accelerator group for the accelerators (or, as they're called in
167      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
168      Ctrl+<key> is an accelerator). */
169   accel_group = gtk_accel_group_new();
170   gtk_window_add_accel_group(GTK_WINDOW(print_w), accel_group);
171 #endif
172
173   /* Vertical enclosing container for each row of widgets */
174   main_vb = gtk_vbox_new(FALSE, 5);
175   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
176   gtk_container_add(GTK_CONTAINER(print_w), main_vb);
177   gtk_widget_show(main_vb);
178
179 /*****************************************************/
180
181   /*** printer frame ***/
182   printer_fr = gtk_frame_new("Printer");
183   gtk_box_pack_start(GTK_BOX(main_vb), printer_fr, FALSE, FALSE, 0);
184   gtk_widget_show(printer_fr);
185   printer_vb = gtk_vbox_new(FALSE, 5);
186   gtk_container_border_width(GTK_CONTAINER(printer_vb), 5);
187   gtk_container_add(GTK_CONTAINER(printer_fr), printer_vb);
188   gtk_widget_show(printer_vb);
189
190   /* "Plain text" / "Postscript" / "PDML", ... radio buttons */
191   text_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "Plain _text", accel_group);
192   if (args->format == PR_FMT_TEXT)
193     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(text_rb), TRUE);
194   gtk_tooltips_set_tip (tooltips, text_rb, ("Print output in ascii \"plain text\" format. If you're unsure, use this format."), NULL);
195   gtk_box_pack_start(GTK_BOX(printer_vb), text_rb, FALSE, FALSE, 0);
196   gtk_widget_show(text_rb);
197
198   ps_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "_PostScript", accel_group);
199   if (args->format == PR_FMT_PS)
200     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ps_rb), TRUE);
201   gtk_tooltips_set_tip (tooltips, ps_rb, ("Print output in \"postscript\" format, for postscript capable printers or print servers."), NULL);
202   gtk_box_pack_start(GTK_BOX(printer_vb), ps_rb, FALSE, FALSE, 0);
203   gtk_widget_show(ps_rb);
204
205   pdml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PDM_L (XML: Packet Details Markup Language)", accel_group);
206   if (args->format == PR_FMT_PDML)
207     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(pdml_rb), TRUE);
208   gtk_tooltips_set_tip (tooltips, pdml_rb, (
209       "Print output in \"PDML\" (Packet Details Markup Language), "
210       "an XML based packet data interchange format. "
211       "Usually used in combination with the \"Output to file\" option to export packet data into an XML file."), NULL);
212   gtk_box_pack_start(GTK_BOX(printer_vb), pdml_rb, FALSE, FALSE, 0);
213   gtk_widget_show(pdml_rb);
214
215   psml_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(text_rb, "PSML (XML: Packet Summary Markup Language)", accel_group);
216   if (args->format == PR_FMT_PSML)
217     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(psml_rb), TRUE);
218   gtk_tooltips_set_tip (tooltips, psml_rb, (
219       "Print output in \"PSML\" (Packet Summary Markup Language), "
220       "an XML based packet summary interchange format. "
221       "Usually used in combination with the \"Output to file\" option to export packet data into an XML file."), NULL);
222   gtk_box_pack_start(GTK_BOX(printer_vb), psml_rb, FALSE, FALSE, 0);
223   gtk_widget_show(psml_rb);
224
225   /* printer table */
226 #ifndef _WIN32
227   printer_tb = gtk_table_new(2, 3, FALSE);
228 #else
229   printer_tb = gtk_table_new(2, 2, FALSE);
230 #endif
231   gtk_box_pack_start(GTK_BOX(printer_vb), printer_tb, FALSE, FALSE, 0);
232   gtk_table_set_row_spacings(GTK_TABLE(printer_tb), 5);
233   gtk_table_set_col_spacings(GTK_TABLE(printer_tb), 5);
234   gtk_widget_show(printer_tb);
235
236
237   /* Output to file button */
238   dest_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Output to _file:", accel_group);
239   if (args->to_file)
240     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dest_cb), TRUE);
241   gtk_tooltips_set_tip (tooltips, dest_cb, ("Output to file instead of printer"), NULL);
242   gtk_table_attach_defaults(GTK_TABLE(printer_tb), dest_cb, 0, 1, 0, 1);
243   gtk_widget_show(dest_cb);
244   
245   /* File text entry and "Browse" button */
246   file_te = gtk_entry_new();
247   OBJECT_SET_DATA(dest_cb, PRINT_FILE_TE_KEY, file_te);
248   gtk_tooltips_set_tip (tooltips, file_te, ("Enter Output filename"), NULL);
249   gtk_entry_set_text(GTK_ENTRY(file_te), args->file);
250   gtk_table_attach_defaults(GTK_TABLE(printer_tb), file_te, 1, 2, 0, 1);
251   gtk_widget_set_sensitive(file_te, args->to_file);
252   gtk_widget_show(file_te);
253   if (args->to_file)
254     gtk_widget_grab_focus(file_te);
255
256   file_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_BROWSE);
257   OBJECT_SET_DATA(dest_cb, PRINT_FILE_BT_KEY, file_bt);
258   OBJECT_SET_DATA(file_bt, E_FILE_TE_PTR_KEY, file_te);
259   gtk_tooltips_set_tip (tooltips, file_bt, ("Browse output filename in filesystem"), NULL);
260   gtk_table_attach_defaults(GTK_TABLE(printer_tb), file_bt, 2, 3, 0, 1);
261   gtk_widget_set_sensitive(file_bt, args->to_file);
262   gtk_widget_show(file_bt);
263
264   /* Command label and text entry */
265 #ifndef _WIN32
266   cmd_lb = gtk_label_new("Print command:");
267   OBJECT_SET_DATA(dest_cb, PRINT_CMD_LB_KEY, cmd_lb);
268   gtk_misc_set_alignment(GTK_MISC(cmd_lb), 1.0, 0.5);
269   gtk_table_attach_defaults(GTK_TABLE(printer_tb), cmd_lb, 0, 1, 1, 2);
270   gtk_widget_set_sensitive(cmd_lb, !args->to_file);
271   gtk_widget_show(cmd_lb);
272
273   cmd_te = gtk_entry_new();
274   OBJECT_SET_DATA(dest_cb, PRINT_CMD_TE_KEY, cmd_te);
275   gtk_tooltips_set_tip (tooltips, cmd_te, ("Enter print command"), NULL);
276   gtk_entry_set_text(GTK_ENTRY(cmd_te), args->cmd);
277   gtk_table_attach_defaults(GTK_TABLE(printer_tb), cmd_te, 1, 2, 1, 2);
278   gtk_widget_set_sensitive(cmd_te, !args->to_file);
279   gtk_widget_show(cmd_te);
280 #endif
281
282   SIGNAL_CONNECT(dest_cb, "toggled", print_cmd_toggle_dest, NULL);
283   SIGNAL_CONNECT(file_bt, "clicked", select_file_cb, "Ethereal: Print to File");
284
285
286 /*****************************************************/
287
288   /*** hor box for range and format frames ***/
289   packet_hb = gtk_hbox_new(FALSE, 5);
290   gtk_container_add(GTK_CONTAINER(main_vb), packet_hb);
291   gtk_widget_show(packet_hb);
292
293   /*** packet range frame ***/
294   range_fr = gtk_frame_new("Packet Range");
295   gtk_box_pack_start(GTK_BOX(packet_hb), range_fr, FALSE, FALSE, 0);
296   gtk_widget_show(range_fr);
297
298   range_tb = range_new(&args->range
299 #if GTK_MAJOR_VERSION < 2
300   , accel_group
301 #endif
302   );
303   gtk_container_add(GTK_CONTAINER(range_fr), range_tb);
304   gtk_widget_show(range_tb);
305
306 /*****************************************************/
307
308   /*** packet format frame ***/
309   format_fr = gtk_frame_new("Packet Format");
310   gtk_box_pack_start(GTK_BOX(packet_hb), format_fr, TRUE, TRUE, 0);
311   gtk_widget_show(format_fr);
312   format_vb = gtk_vbox_new(FALSE, 5);
313   gtk_container_border_width(GTK_CONTAINER(format_vb), 5);
314   gtk_container_add(GTK_CONTAINER(format_fr), format_vb);
315   gtk_widget_show(format_vb);
316
317   /* "Print summary line" check button */
318   summary_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet summary line", accel_group);
319   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(summary_cb), args->print_summary);
320   SIGNAL_CONNECT(summary_cb, "clicked", print_cmd_toggle_detail, print_w);
321   gtk_tooltips_set_tip (tooltips, summary_cb, ("Output of a packet summary line, like in the packet list"), NULL);
322   gtk_container_add(GTK_CONTAINER(format_vb), summary_cb);
323   gtk_widget_show(summary_cb);
324
325
326   /* "Details" check button */
327   details_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet details:", accel_group);
328   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(details_cb), args->print_dissections != print_dissections_none);
329   SIGNAL_CONNECT(details_cb, "clicked", print_cmd_toggle_detail, print_w);
330   gtk_tooltips_set_tip (tooltips, details_cb, ("Output format of the selected packet details (protocol tree)."), NULL);
331   gtk_container_add(GTK_CONTAINER(format_vb), details_cb);
332   gtk_widget_show(details_cb);
333
334   /*** packet details ***/
335   details_hb = gtk_hbox_new(FALSE, 6);
336   gtk_container_border_width(GTK_CONTAINER(details_hb), 0);
337   gtk_container_add(GTK_CONTAINER(format_vb), details_hb);
338   gtk_widget_show(details_hb);
339
340   details_vb = gtk_vbox_new(FALSE, 6);
341   gtk_container_border_width(GTK_CONTAINER(details_vb), 0);
342   gtk_container_add(GTK_CONTAINER(details_hb), details_vb);
343   gtk_widget_show(details_vb);
344
345   details_vb = gtk_vbox_new(FALSE, 6);
346   gtk_container_border_width(GTK_CONTAINER(details_vb), 0);
347   gtk_container_add(GTK_CONTAINER(details_hb), details_vb);
348   gtk_widget_show(details_vb);
349
350   /* "All collapsed"/"As displayed"/"All Expanded" radio buttons */
351   collapse_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "All co_llapsed", accel_group);
352   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(collapse_all_rb), args->print_dissections == print_dissections_collapsed);
353   gtk_tooltips_set_tip (tooltips, collapse_all_rb, ("Output of the packet details tree \"collapsed\""), NULL);
354   gtk_container_add(GTK_CONTAINER(details_vb), collapse_all_rb);
355   gtk_widget_show(collapse_all_rb);
356
357   as_displayed_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(collapse_all_rb, "As displa_yed", accel_group);
358   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(as_displayed_rb), args->print_dissections == print_dissections_as_displayed);
359   gtk_tooltips_set_tip (tooltips, as_displayed_rb, ("Output of the packet details tree \"as displayed\""), NULL);
360   gtk_container_add(GTK_CONTAINER(details_vb), as_displayed_rb);
361   gtk_widget_show(as_displayed_rb);
362
363   expand_all_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(collapse_all_rb, "All e_xpanded", accel_group);
364   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(expand_all_rb), args->print_dissections == print_dissections_expanded);
365   gtk_tooltips_set_tip (tooltips, expand_all_rb, ("Output of the packet details tree \"expanded\""), NULL);
366   gtk_container_add(GTK_CONTAINER(details_vb), expand_all_rb);
367   gtk_widget_show(expand_all_rb);
368
369   /* "Print hex" check button. */
370   hex_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Packet bytes", accel_group);
371   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(hex_cb), args->print_hex);
372   SIGNAL_CONNECT(hex_cb, "clicked", print_cmd_toggle_detail, print_w);
373   gtk_tooltips_set_tip (tooltips, hex_cb, ("Add a hexdump of the packet data"), NULL);
374   gtk_container_add(GTK_CONTAINER(format_vb), hex_cb);
375   gtk_widget_show(hex_cb);
376
377   /* seperator */
378   sep = gtk_hseparator_new();
379   gtk_container_add(GTK_CONTAINER(format_vb), sep);
380   gtk_widget_show(sep);
381
382   /* "Each packet on a new page" check button. */
383   formfeed_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC("Each packet on a new page", accel_group);
384   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(formfeed_cb), args->print_formfeed);
385   gtk_tooltips_set_tip (tooltips, formfeed_cb, ("When checked, a new page will be used for each packet. "
386       "This is done by adding a formfeed (or similar) between the packet outputs."), NULL);
387   gtk_container_add(GTK_CONTAINER(format_vb), formfeed_cb);
388   gtk_widget_show(formfeed_cb);
389
390
391   OBJECT_SET_DATA(print_w, PRINT_ARGS_KEY, args);
392   OBJECT_SET_DATA(print_w, PRINT_SUMMARY_CB_KEY, summary_cb);
393   OBJECT_SET_DATA(print_w, PRINT_DETAILS_CB_KEY, details_cb);
394   OBJECT_SET_DATA(print_w, PRINT_COLLAPSE_ALL_RB_KEY, collapse_all_rb);
395   OBJECT_SET_DATA(print_w, PRINT_AS_DISPLAYED_RB_KEY, as_displayed_rb);
396   OBJECT_SET_DATA(print_w, PRINT_EXPAND_ALL_RB_KEY, expand_all_rb);
397   OBJECT_SET_DATA(print_w, PRINT_HEX_CB_KEY, hex_cb);
398
399 /*****************************************************/
400
401
402   /* Button row */
403   bbox = dlg_button_row_new(GTK_STOCK_PRINT, GTK_STOCK_CANCEL, NULL);
404   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
405   gtk_widget_show(bbox);
406
407   ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_PRINT);
408
409   OBJECT_SET_DATA(print_w, PRINT_BT_KEY, ok_bt);
410
411   OBJECT_SET_DATA(ok_bt, PRINT_PS_RB_KEY, ps_rb);
412   OBJECT_SET_DATA(ok_bt, PRINT_PDML_RB_KEY, pdml_rb);
413   OBJECT_SET_DATA(ok_bt, PRINT_PSML_RB_KEY, psml_rb);
414   OBJECT_SET_DATA(ok_bt, PRINT_DEST_CB_KEY, dest_cb);
415 #ifndef _WIN32
416   OBJECT_SET_DATA(ok_bt, PRINT_CMD_TE_KEY, cmd_te);
417 #endif
418
419   OBJECT_SET_DATA(ok_bt, PRINT_ARGS_KEY, args);
420   OBJECT_SET_DATA(ok_bt, PRINT_FILE_TE_KEY, file_te);
421   OBJECT_SET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY, summary_cb);
422   OBJECT_SET_DATA(ok_bt, PRINT_DETAILS_CB_KEY, details_cb);
423   OBJECT_SET_DATA(ok_bt, PRINT_COLLAPSE_ALL_RB_KEY, collapse_all_rb);
424   OBJECT_SET_DATA(ok_bt, PRINT_AS_DISPLAYED_RB_KEY, as_displayed_rb);
425   OBJECT_SET_DATA(ok_bt, PRINT_EXPAND_ALL_RB_KEY, expand_all_rb);
426   OBJECT_SET_DATA(ok_bt, PRINT_HEX_CB_KEY, hex_cb);
427   OBJECT_SET_DATA(ok_bt, PRINT_FORMFEED_CB_KEY, formfeed_cb);
428   SIGNAL_CONNECT(ok_bt, "clicked", print_ok_cb, print_w);
429   gtk_tooltips_set_tip (tooltips, ok_bt, ("Start printing"), NULL);
430   gtk_widget_grab_default(ok_bt);
431
432   cancel_bt  = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
433   SIGNAL_CONNECT(cancel_bt, "clicked", print_close_cb, print_w);
434   gtk_tooltips_set_tip (tooltips, cancel_bt, ("Cancel print and exit dialog"), NULL);
435
436   /* Catch the "activate" signal on the "Command" and "File" text entries,
437      so that if the user types Return there, we act as if the "OK" button
438      had been selected, as happens if Return is typed if some widget
439      that *doesn't* handle the Return key has the input focus. */
440
441 #ifndef _WIN32
442   dlg_set_activate(cmd_te, ok_bt);
443 #endif
444   dlg_set_activate(file_te, ok_bt);
445
446   /* Catch the "key_press_event" signal in the window, so that we can catch
447      the ESC key being pressed and act as if the "Cancel" button had
448      been selected. */
449   dlg_set_cancel(print_w, cancel_bt);
450
451   gtk_widget_show(print_w);
452 }
453
454
455 /* user changed "print to" destination */
456 static void
457 print_cmd_toggle_dest(GtkWidget *widget, gpointer data _U_)
458 {
459 #ifndef _WIN32
460   GtkWidget     *cmd_lb, *cmd_te;
461 #endif
462   GtkWidget     *file_bt, *file_te;
463   int            to_file;
464
465 #ifndef _WIN32
466   cmd_lb = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_CMD_LB_KEY));
467   cmd_te = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_CMD_TE_KEY));
468 #endif
469   file_bt = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_FILE_BT_KEY));
470   file_te = GTK_WIDGET(OBJECT_GET_DATA(widget, PRINT_FILE_TE_KEY));
471
472   to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
473 #ifndef _WIN32
474   gtk_widget_set_sensitive(cmd_lb, !to_file);
475   gtk_widget_set_sensitive(cmd_te, !to_file);
476 #endif
477   gtk_widget_set_sensitive(file_bt, to_file);
478   gtk_widget_set_sensitive(file_te, to_file);
479 }
480
481
482 /* user changed "packet details" */
483 static void
484 print_cmd_toggle_detail(GtkWidget *widget _U_, gpointer data)
485 {
486   GtkWidget     *print_bt, *summary_cb, *details_cb, *collapse_all_rb, *expand_all_rb, *as_displayed_rb, *hex_cb;
487   gboolean      print_detail;
488
489
490   print_bt = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_BT_KEY));
491   summary_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_SUMMARY_CB_KEY));
492   details_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_DETAILS_CB_KEY));
493   collapse_all_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_COLLAPSE_ALL_RB_KEY));
494   as_displayed_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_AS_DISPLAYED_RB_KEY));
495   expand_all_rb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_EXPAND_ALL_RB_KEY));
496   hex_cb = GTK_WIDGET(OBJECT_GET_DATA(data, PRINT_HEX_CB_KEY));
497
498   /* is user disabled details, disable the corresponding buttons */
499   print_detail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (details_cb));
500   gtk_widget_set_sensitive(collapse_all_rb, print_detail);
501   gtk_widget_set_sensitive(as_displayed_rb, print_detail);
502   gtk_widget_set_sensitive(expand_all_rb, print_detail);
503
504   /* if user selected nothing to print at all, disable the "ok" button */
505   gtk_widget_set_sensitive(print_bt, 
506       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (summary_cb)) ||
507       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (details_cb)) ||
508       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_cb)));
509 }
510
511
512 static void
513 print_ok_cb(GtkWidget *ok_bt, gpointer parent_w)
514 {
515   GtkWidget     *button;
516   print_args_t  *args;
517   const gchar   *g_dest;
518   gchar         *f_name;
519   gchar         *dirname;
520 #ifdef _WIN32
521   int win_printer_flag = FALSE;
522 #endif
523
524   args = (print_args_t *)OBJECT_GET_DATA(ok_bt, PRINT_ARGS_KEY);
525
526   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_DEST_CB_KEY);
527   args->to_file = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
528
529   if (args->to_file) {
530     g_dest = gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
531                                                           PRINT_FILE_TE_KEY)));
532     if (!g_dest[0]) {
533       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
534         "Printing to file, but no file specified.");
535       return;
536     }
537     g_free(args->file);
538     args->file = g_strdup(g_dest);
539     /* Save the directory name for future file dialogs. */
540     f_name = g_strdup(g_dest);
541     dirname = get_dirname(f_name);  /* Overwrites f_name */
542     set_last_open_dir(dirname);
543     g_free(f_name);
544   } else {
545 #ifdef _WIN32
546     win_printer_flag = TRUE;
547     /*XXX should use temp file stuff in util routines */
548     g_free(args->file);
549     args->file = g_strdup(tmpnam(NULL));
550     args->to_file = TRUE;
551 #else
552     g_free(args->cmd);
553     args->cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(OBJECT_GET_DATA(ok_bt,
554       PRINT_CMD_TE_KEY))));
555 #endif
556   }
557
558   args->format = PR_FMT_TEXT;
559   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PS_RB_KEY);
560   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
561     args->format = PR_FMT_PS;
562   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PDML_RB_KEY);
563   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
564     args->format = PR_FMT_PDML;
565   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_PSML_RB_KEY);
566   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button)))
567     args->format = PR_FMT_PSML;
568
569   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_SUMMARY_CB_KEY);
570   args->print_summary = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
571
572   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_COLLAPSE_ALL_RB_KEY);
573   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
574     args->print_dissections = print_dissections_collapsed;
575   }
576   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_AS_DISPLAYED_RB_KEY);
577   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
578     args->print_dissections = print_dissections_as_displayed;
579   }
580   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_EXPAND_ALL_RB_KEY);
581   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
582     args->print_dissections = print_dissections_expanded;
583   }
584
585   /* the details setting has priority over the radio buttons */
586   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_DETAILS_CB_KEY);
587   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button))) {
588     args->print_dissections = print_dissections_none;
589   }
590
591   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_HEX_CB_KEY);
592   args->print_hex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
593
594   button = (GtkWidget *)OBJECT_GET_DATA(ok_bt, PRINT_FORMFEED_CB_KEY);
595   args->print_formfeed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (button));
596
597
598   gtk_widget_destroy(GTK_WIDGET(parent_w));
599
600   /* Now print the packets */
601   switch (print_packets(&cfile, args)) {
602
603   case PP_OK:
604     break;
605
606   case PP_OPEN_ERROR:
607     if (args->to_file)
608       open_failure_alert_box(args->file, errno, TRUE);
609     else
610       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't run print command %s.",
611         args->cmd);
612     break;
613
614   case PP_WRITE_ERROR:
615     if (args->to_file)
616       write_failure_alert_box(args->file, errno);
617     else
618       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
619         "Error writing to print command: %s", strerror(errno));
620     break;
621   }
622
623 #ifdef _WIN32
624   if (win_printer_flag) {
625     print_mswin(args->file);
626
627     /* trash temp file */
628     remove(args->file);
629   }
630 #endif
631 }
632
633 static void
634 print_close_cb(GtkWidget *close_bt _U_, gpointer parent_w)
635 {
636   gtk_grab_remove(GTK_WIDGET(parent_w));
637   gtk_widget_destroy(GTK_WIDGET(parent_w));
638 }
639
640 static void
641 print_destroy_cb(GtkWidget *win, gpointer user_data _U_)
642 {
643   GtkWidget     *fs;
644
645   /* Is there a file selection dialog associated with this
646      Print File dialog? */
647   fs = OBJECT_GET_DATA(win, E_FILE_SEL_DIALOG_PTR_KEY);
648
649   if (fs != NULL) {
650     /* Yes.  Destroy it. */
651     gtk_widget_destroy(fs);
652   }
653
654   /* Note that we no longer have a "Print" dialog box. */
655   print_w = NULL;
656 }
657
658
659
660