Rename "save_LIBS" to "ethereal_save_LIBS", to reduce the risk of a name
[obnox/wireshark/wip.git] / colors.c
1 /* colors.c
2  * Definitions for color structures and routines
3  *
4  * $Id: colors.c,v 1.28 2000/01/03 06:59:07 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #include <errno.h>
37 #include <sys/types.h>
38
39 #include "gtk/main.h"
40 #include "packet.h"
41 #include "colors.h"
42 #include "file.h"
43 #include "dfilter.h"
44 #include "simple_dialog.h"
45 #include "ui_util.h"
46
47 extern capture_file cf;
48
49 static color_filter_t *new_color_filter(colfilter *filters, gchar *name,
50                                  gchar *filter_string);
51 static gboolean read_filters(colfilter *filter);
52
53 static GtkWidget* colorize_dialog_new(colfilter *filter);
54 static void add_filter_to_clist(gpointer filter_arg, gpointer clist_arg);
55 static void color_filter_up_cb(GtkButton *button, gpointer user_data);
56 static void color_filter_down_cb(GtkButton *button, gpointer user_data);
57 static void remember_selected_row(GtkCList *clist, gint row, gint column,
58                                  GdkEvent *event, gpointer user_data);
59 static void color_destroy_cb(GtkButton *button, gpointer user_data);
60 static void destroy_edit_dialog_cb(gpointer filter_arg, gpointer dummy);
61 static void color_new_cb(GtkButton *button, gpointer user_data);
62 static void color_edit_cb(GtkButton *button, gpointer user_data);
63 static void color_delete_cb(GtkWidget *widget, gpointer user_data);
64 static void color_save_cb(GtkButton *button, gpointer user_data);
65 static void color_ok_cb(GtkButton *button, gpointer user_data);
66 static void color_cancel_cb(GtkWidget *widget, gpointer user_data);
67 static void color_apply_cb(GtkButton *button, gpointer user_data);
68
69 static void edit_color_filter_dialog_new(colfilter *filter,
70                                  GtkWidget *color_filters,
71                                  GtkWidget **colorize_filter_name,
72                                  GtkWidget **colorize_filter_text);
73 static void edit_color_filter_destroy_cb(GtkObject *object,
74                                  gpointer user_data);
75 static void edit_color_filter_fg_cb(GtkButton *button, gpointer user_data);
76 static void edit_color_filter_bg_cb(GtkButton *button, gpointer user_data);
77 static void edit_color_filter_ok_cb(GtkButton *button, gpointer user_data);
78 static void edit_color_filter_cancel_cb(GtkObject *object, gpointer user_data);
79
80 static GtkWidget* color_sel_win_new(color_filter_t *colorf, gboolean);
81 static void color_sel_ok_cb(GtkButton *button, gpointer user_data);
82 static void color_sel_cancel_cb(GtkObject *object, gpointer user_data);
83
84 static gboolean get_color(GdkColor *new_color);
85
86 GSList *filter_list;
87
88 static GdkColormap*     sys_cmap;
89 static GdkColormap*     our_cmap = NULL;
90
91 static GtkWidget *colorize_win;
92
93 static gchar *titles[2] = { "Name", "Filter String" };
94 GdkColor        WHITE = { 0, 65535, 65535, 65535 };
95 GdkColor        BLACK = { 0, 0, 0, 0 };
96
97 #define COLOR_EDIT_LB           "color_edit_lb"
98 #define COLOR_FILTERS_CL        "color_filters_cl"
99 #define COLOR_FILTER            "color_filter"
100 #define COLOR_SELECTION_FG      "color_selection_fg"
101 #define COLOR_SELECTION_BG      "color_selection_bg"
102 #define COLOR_SELECTION_PARENT  "color_selection_parent"
103
104 /* This structure is used to allow you to compile in default colors if
105  * you wish.  They can be later changed by a user.
106  */
107 #ifdef READ_DEFAULT_COLOR_LIST
108 struct _default_colors {
109         gchar* proto;
110         gchar* color; /* background only */
111 } default_colors[]  = {
112         {"arp", "green2"},
113         {"ip",  "light red"},
114         {"tcp",  "light blue"}
115 };
116 #endif
117
118 colfilter *
119 colfilter_new(void)
120 {
121   colfilter *filter;
122   gboolean got_white, got_black;
123 #ifdef READ_DEFAULT_COLOR_LIST
124   color_filter_t *colorf;
125   gint i;
126   GdkColor color;
127 #endif
128
129   filter = (colfilter *)g_malloc(sizeof(colfilter));
130   filter->num_of_filters = 0;
131
132   sys_cmap = gdk_colormap_get_system();
133
134   /* Allocate "constant" colors. */
135   got_white = get_color(&WHITE);
136   got_black = get_color(&BLACK);
137
138   /* Got milk? */
139   if (!got_white) {
140     if (!got_black)
141       simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate colors black or white.");
142     else
143       simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color white.");
144   } else {
145     if (!got_black)
146       simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color black.");
147   }
148
149 #ifdef READ_DEFAULT_COLOR_LIST
150   /* Now process defaults */
151   for (i = 0 ; i < sizeof default_colors/sizeof (struct _default_colors); i++){
152         gdk_color_parse(default_colors[i].color, &color);
153         
154         if( !get_color(&color)){
155                 /* oops */
156                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color %s.",
157                     default_colors[i].color);
158         }
159
160         colorf = new_color_filter(filter, default_colors[i].proto,
161             default_colors[i].proto);
162         colorf->bg_color = color;
163
164         if (dfilter_compile(default_colors[i].proto,
165             &colorf->c_colorfilter) != 0) {
166                 simple_dialog(ESD_TYPE_WARN, NULL,
167                   "Cannot compile default color filter %s.\n%s",
168                   default_colors[i].proto, dfilter_error_msg);
169                 /* should reject this filter */
170         }
171         filter->num_of_filters++;
172   }
173 #endif
174   read_filters(filter);
175   return filter;
176 }
177
178 static color_filter_t *
179 new_color_filter(colfilter *filters, gchar *name, gchar *filter_string)
180 {
181         color_filter_t *colorf;
182
183         colorf = (color_filter_t *)g_malloc(sizeof (color_filter_t));
184         colorf->filter_name = g_strdup(name);
185         colorf->filter_text = g_strdup(filter_string);
186         colorf->bg_color = WHITE;
187         colorf->fg_color = BLACK;
188         colorf->c_colorfilter = NULL;
189         colorf->edit_dialog = NULL;
190         filter_list = g_slist_append(filter_list, colorf);
191         return colorf;
192 }
193
194 static void
195 delete_color_filter(color_filter_t *colorf)
196 {
197         if (colorf->filter_name != NULL)
198           g_free(colorf->filter_name);
199         if (colorf->filter_text != NULL)
200           g_free(colorf->filter_text);
201         if (colorf->c_colorfilter != NULL)
202           dfilter_destroy(colorf->c_colorfilter);
203         filter_list = g_slist_remove(filter_list, colorf);
204         g_free(colorf);
205 }
206
207 static gboolean
208 read_filters(colfilter *filter)
209 {
210         /* TODO: Lots more syntax checking on the file */
211         /* I hate these fixed length names! TODO: make more dynamic */
212         /* XXX - buffer overflow possibility here */
213         gchar name[256],filter_exp[256], buf[1024];
214         guint16 fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
215         GdkColor fg_color, bg_color;
216         color_filter_t *colorf;
217         int i;
218         FILE *f;
219         gchar *path;
220         gchar *fname = PF_DIR "/colorfilters";
221         dfilter *temp_dfilter;
222
223         /* decide what file to open (from dfilter code) */
224
225         /* should only be called by colors_init.
226          */
227         if(filter == NULL)
228                 return FALSE;
229         /* we have a clist */
230
231         path = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(fname) +  4);
232         sprintf(path, "%s/%s", getenv("HOME"), fname);
233
234         if ((f = fopen(path, "r")) == NULL) {
235           if (errno != ENOENT) {
236             simple_dialog(ESD_TYPE_WARN, NULL,
237               "Could not open filter file\n\"%s\": %s.", path,
238               strerror(errno));
239           }
240           g_free(path);
241           return FALSE;
242         }
243         g_free(path);
244
245         i = 0;
246
247         do{
248           if(!fgets(buf,sizeof buf, f))
249                 break;
250                 
251           if(strspn( buf," \t") == (strchr(buf,'*') - buf)){
252                 /* leading # comment */
253                 continue;
254           }
255
256           /* we get the @ delimiter.  It is not in any strings */
257           if(sscanf(buf," @%[^@]@%[^@]@[%hu,%hu,%hu][%hu,%hu,%hu]",
258                 name, filter_exp, &bg_r, &bg_g, &bg_b, &fg_r, &fg_g, &fg_b) == 8){
259                 /* we got a filter */
260
261             if(dfilter_compile(filter_exp, &temp_dfilter) != 0){
262                 simple_dialog(ESD_TYPE_WARN, NULL,
263                  "Could not compile color filter %s from saved filters.\n%s",
264                  name, dfilter_error_msg);
265                 continue;
266             }
267             colorf = new_color_filter(filter, name, filter_exp);
268             colorf->c_colorfilter = temp_dfilter;
269             filter->num_of_filters++;
270             fg_color.red = fg_r;
271             fg_color.green = fg_g;
272             fg_color.blue = fg_b;
273             bg_color.red = bg_r;
274             bg_color.green = bg_g;
275             bg_color.blue = bg_b;
276             if( !get_color(&fg_color)){
277                 /* oops */
278                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate fg color specified"
279                   "in input file for %s.", name);
280
281                 i++;
282                 continue;
283             }
284             if( !get_color(&bg_color)){
285                 /* oops */
286                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate bg color specified"
287                   "in input file for %s.", name);
288                 i++;
289                 continue;
290             }
291
292             colorf->bg_color = bg_color;
293             colorf->fg_color = fg_color;
294             i++;
295           }    /* if sscanf */
296         } while( !feof(f));
297         return TRUE;
298 }
299
300 static void
301 write_filter(gpointer filter_arg, gpointer file_arg)
302 {
303         color_filter_t *colorf = filter_arg;
304         FILE *f = file_arg;
305
306         fprintf(f,"@%s@%s@[%d,%d,%d][%d,%d,%d]\n",
307             colorf->filter_name,
308             colorf->filter_text,
309             colorf->bg_color.red,
310             colorf->bg_color.green,
311             colorf->bg_color.blue,
312             colorf->fg_color.red,
313             colorf->fg_color.green,
314             colorf->fg_color.blue);
315 }
316         
317 static gboolean
318 write_filters(colfilter *filter)
319 {
320         FILE *f;
321         gchar *path;
322         gchar *name = PF_DIR "/colorfilters";
323         /* decide what file to open (from dfilter code) */
324         path = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(name) +  4);
325         sprintf(path, "%s/%s", getenv("HOME"), name);
326
327         if ((f = fopen(path, "w+")) == NULL) {
328           simple_dialog(ESD_TYPE_WARN, NULL,
329                 "Could not open\n%s\nfor writing: %s.",
330                 path, strerror(errno));
331           g_free(path);
332           return FALSE;
333         }
334         fprintf(f,"# DO NOT EDIT THIS FILE!  It was created by Ethereal\n");
335         g_slist_foreach(filter_list, write_filter, f);
336         fclose(f);
337         g_free(path);
338         return TRUE;
339 }
340
341                 
342 /* ===================== USER INTERFACE ====================== */
343
344 /* Callback for the "Display:Colorize Display" menu item. */
345 void
346 color_display_cb(GtkWidget *w, gpointer d)
347 {
348   if (colorize_win != NULL) {
349     /* There's already a color dialog box active; reactivate it. */
350     reactivate_window(colorize_win);
351   } else {
352     /* Create a new "Colorize Display" dialog. */
353     colorize_win = colorize_dialog_new(cf.colors);
354   }
355 }
356
357 /* Create the "Add color to protocols" dialog. */
358 static GtkWidget*
359 colorize_dialog_new (colfilter *filter)
360 {
361   GtkWidget *color_win;
362   GtkWidget *vbox1;
363   GtkWidget *hbox1;
364   GtkWidget *vbox2;
365   GtkWidget *color_filter_up;
366   GtkWidget *label4;
367   GtkWidget *color_filter_down;
368   GtkWidget *scrolledwindow1;
369   GtkWidget *color_filters;
370   GtkWidget *hbox2;
371   GtkWidget *color_new;
372   GtkWidget *color_edit;
373   GtkWidget *color_delete;
374   GtkWidget *color_save;
375   GtkWidget *hbox3;
376   GtkWidget *color_ok;
377   GtkWidget *color_apply;
378   GtkWidget *color_cancel;
379   GtkTooltips *tooltips;
380
381   filter->row_selected = -1; /* no row selected */
382   tooltips = gtk_tooltips_new ();
383
384   color_win = gtk_window_new (GTK_WINDOW_DIALOG);
385   gtk_object_set_data (GTK_OBJECT (color_win), "color_win", color_win);
386   gtk_window_set_title (GTK_WINDOW (color_win), ("Add color to protocols"));
387
388   vbox1 = gtk_vbox_new (FALSE, 0);
389   gtk_widget_ref (vbox1);
390   gtk_object_set_data_full (GTK_OBJECT (color_win), "vbox1", vbox1,
391                             (GtkDestroyNotify) gtk_widget_unref);
392   gtk_widget_show (vbox1);
393   gtk_container_add (GTK_CONTAINER (color_win), vbox1);
394
395   hbox1 = gtk_hbox_new (FALSE, 0);
396   gtk_widget_ref (hbox1);
397   gtk_object_set_data_full (GTK_OBJECT (color_win), "hbox1", hbox1,
398                             (GtkDestroyNotify) gtk_widget_unref);
399   gtk_widget_show (hbox1);
400   gtk_box_pack_start (GTK_BOX (vbox1), hbox1, TRUE, TRUE, 0);
401
402   vbox2 = gtk_vbox_new (TRUE, 0);
403   gtk_widget_ref (vbox2);
404   gtk_object_set_data_full (GTK_OBJECT (color_win), "vbox2", vbox2,
405                             (GtkDestroyNotify) gtk_widget_unref);
406   gtk_widget_show (vbox2);
407   gtk_box_pack_start (GTK_BOX (hbox1), vbox2, FALSE, TRUE, 0);
408   gtk_widget_set_usize (vbox2, 150, -2);
409
410   color_filter_up = gtk_button_new_with_label (("Up"));
411   gtk_widget_ref (color_filter_up);
412   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_filter_up", color_filter_up,
413                             (GtkDestroyNotify) gtk_widget_unref);
414   gtk_widget_show (color_filter_up);
415   gtk_box_pack_start (GTK_BOX (vbox2), color_filter_up, FALSE, FALSE, 0);
416   gtk_tooltips_set_tip (tooltips, color_filter_up, ("Move filter higher in list"), NULL);
417
418   label4 = gtk_label_new (("Move filter\nup or down\n[List is processed \n"
419                           "in order until\nmatch is found]"));
420   gtk_widget_ref (label4);
421   gtk_object_set_data_full (GTK_OBJECT (color_win), "label4", label4,
422                             (GtkDestroyNotify) gtk_widget_unref);
423   gtk_widget_show (label4);
424   gtk_box_pack_start (GTK_BOX (vbox2), label4, FALSE, FALSE, 0);
425
426   color_filter_down = gtk_button_new_with_label (("Down"));
427   gtk_widget_ref (color_filter_down);
428   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_filter_down", color_filter_down,
429                             (GtkDestroyNotify) gtk_widget_unref);
430   gtk_widget_show (color_filter_down);
431   gtk_box_pack_start (GTK_BOX (vbox2), color_filter_down, FALSE, FALSE, 0);
432   gtk_tooltips_set_tip (tooltips, color_filter_down, ("Move filter lower in list"), NULL);
433
434   scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
435   gtk_widget_ref (scrolledwindow1);
436   gtk_object_set_data_full (GTK_OBJECT (color_win), "scrolledwindow1", scrolledwindow1,
437                             (GtkDestroyNotify) gtk_widget_unref);
438   gtk_widget_show (scrolledwindow1);
439   gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow1, TRUE, TRUE, 0);
440
441   color_filters = gtk_clist_new_with_titles(2, titles);
442
443 #if 0
444   /* I don't seem to need this, but just in case, I'll if0 it */
445   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_filters",
446                             color_filters,
447                             (GtkDestroyNotify) gtk_widget_unref);
448 #endif
449   g_slist_foreach(filter_list, add_filter_to_clist, color_filters);
450
451   gtk_widget_show (color_filters);
452   gtk_container_add (GTK_CONTAINER (scrolledwindow1), color_filters);
453   gtk_widget_set_usize (color_filters, 300, -2);
454   gtk_clist_set_column_width (GTK_CLIST (color_filters), 0, 80);
455   gtk_clist_set_column_width (GTK_CLIST (color_filters), 1, 80);
456   gtk_clist_column_titles_show (GTK_CLIST (color_filters));
457
458   hbox2 = gtk_hbox_new (FALSE, 0);
459   gtk_widget_ref (hbox2);
460   gtk_object_set_data_full (GTK_OBJECT (color_win), "hbox2", hbox2,
461                             (GtkDestroyNotify) gtk_widget_unref);
462   gtk_widget_show (hbox2);
463   gtk_box_pack_start (GTK_BOX (vbox1), hbox2, TRUE, FALSE, 5);
464   gtk_widget_set_usize (hbox2, -2, 40);
465
466   color_new = gtk_button_new_with_label (("New"));
467   gtk_widget_ref (color_new);
468   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_new", color_new,
469                             (GtkDestroyNotify) gtk_widget_unref);
470   gtk_widget_show (color_new);
471   gtk_box_pack_start (GTK_BOX (hbox2), color_new, TRUE, FALSE, 5);
472   gtk_widget_set_usize (color_new, 50, 30);
473   gtk_tooltips_set_tip (tooltips, color_new, ("Create a new colorization filter after selected filter"), NULL);
474
475   color_edit = gtk_button_new_with_label (("Edit"));
476   gtk_widget_ref (color_edit);
477   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_edit", color_edit,
478                             (GtkDestroyNotify) gtk_widget_unref);
479   gtk_widget_show (color_edit);
480   gtk_widget_set_usize(color_edit, 50, 30);
481   gtk_box_pack_start (GTK_BOX (hbox2), color_edit, TRUE, FALSE, 5);
482   gtk_tooltips_set_tip (tooltips, color_edit, ("Change color of selected filter"), NULL);
483   gtk_widget_set_sensitive (color_edit,
484       (filter->num_of_filters != 0));
485
486   color_delete = gtk_button_new_with_label (("Delete"));
487   gtk_widget_ref (color_delete);
488   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_delete", color_delete,
489                             (GtkDestroyNotify) gtk_widget_unref);
490   gtk_widget_show (color_delete);
491   gtk_box_pack_start (GTK_BOX (hbox2), color_delete, TRUE, FALSE, 5);
492   gtk_widget_set_usize (color_delete, 50, 30);
493   gtk_tooltips_set_tip (tooltips, color_delete, ("Delete selected colorization filter"), NULL);
494
495   color_save = gtk_button_new_with_label (("Save"));
496   gtk_widget_ref (color_save);
497   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_save", color_save,
498                             (GtkDestroyNotify) gtk_widget_unref);
499   gtk_widget_show (color_save);
500   gtk_box_pack_start (GTK_BOX (hbox2), color_save, TRUE, FALSE, 5);
501   gtk_widget_set_usize (color_save, 50, 30);
502   gtk_tooltips_set_tip (tooltips, color_save, ("Save all filters to disk"), NULL);
503
504   hbox3 = gtk_hbox_new (FALSE, 0);
505   gtk_widget_ref (hbox3);
506   gtk_object_set_data_full (GTK_OBJECT (color_win), "hbox3", hbox3,
507                             (GtkDestroyNotify) gtk_widget_unref);
508   gtk_widget_show (hbox3);
509   gtk_box_pack_start (GTK_BOX (vbox1), hbox3, TRUE, FALSE, 5);
510   gtk_widget_set_usize (hbox3, 177, 40);
511
512   color_ok = gtk_button_new_with_label (("OK"));
513   gtk_widget_ref (color_ok);
514   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_ok", color_ok,
515                             (GtkDestroyNotify) gtk_widget_unref);
516   gtk_widget_show (color_ok);
517   gtk_box_pack_start (GTK_BOX (hbox3), color_ok, TRUE, FALSE, 0);
518   gtk_widget_set_usize (color_ok, 50, 30);
519   gtk_tooltips_set_tip (tooltips, color_ok, ("Accept filter list; apply changes"), NULL);
520
521   color_apply = gtk_button_new_with_label (("Apply"));
522   gtk_widget_ref (color_apply);
523   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_apply", color_apply,
524                             (GtkDestroyNotify) gtk_widget_unref);
525   gtk_widget_show (color_apply);
526   gtk_box_pack_start (GTK_BOX (hbox3), color_apply, TRUE, FALSE, 0);
527   gtk_widget_set_usize (color_apply, 50, 30);
528   gtk_tooltips_set_tip (tooltips, color_apply, ("Apply filters in list"), NULL);
529
530   color_cancel = gtk_button_new_with_label (("Cancel"));
531   gtk_widget_ref (color_cancel);
532   gtk_object_set_data_full (GTK_OBJECT (color_win), "color_cancel", color_cancel,
533                             (GtkDestroyNotify) gtk_widget_unref);
534   gtk_widget_show (color_cancel);
535   gtk_box_pack_start (GTK_BOX (hbox3), color_cancel, TRUE, FALSE, 0);
536   gtk_widget_set_usize (color_cancel, 50, 30);
537   gtk_tooltips_set_tip (tooltips, color_cancel, ("No more filter changes; don't apply"), NULL);
538
539   gtk_signal_connect (GTK_OBJECT (color_win), "destroy",
540                       GTK_SIGNAL_FUNC (color_destroy_cb),
541                       NULL);
542   gtk_object_set_data(GTK_OBJECT (color_filter_up), COLOR_FILTERS_CL,
543                       color_filters);
544   gtk_signal_connect (GTK_OBJECT (color_filter_up), "clicked",
545                       GTK_SIGNAL_FUNC (color_filter_up_cb),
546                       filter);
547   gtk_object_set_data(GTK_OBJECT (color_filter_down), COLOR_FILTERS_CL,
548                       color_filters);
549   gtk_signal_connect (GTK_OBJECT (color_filter_down), "clicked",
550                       GTK_SIGNAL_FUNC (color_filter_down_cb),
551                       filter);
552   gtk_signal_connect (GTK_OBJECT (color_filters), "select_row",
553                       GTK_SIGNAL_FUNC (remember_selected_row),
554                       filter);
555   gtk_object_set_data(GTK_OBJECT (color_new), COLOR_EDIT_LB,
556                       color_edit);
557   gtk_object_set_data(GTK_OBJECT (color_new), COLOR_FILTERS_CL,
558                       color_filters);
559   gtk_signal_connect (GTK_OBJECT (color_new), "clicked",
560                       GTK_SIGNAL_FUNC (color_new_cb),
561                       filter);
562   gtk_object_set_data(GTK_OBJECT (color_edit), COLOR_FILTERS_CL,
563                       color_filters);
564   gtk_signal_connect (GTK_OBJECT (color_edit), "clicked",
565                       GTK_SIGNAL_FUNC (color_edit_cb),
566                       filter);
567   gtk_object_set_data(GTK_OBJECT (color_delete), COLOR_EDIT_LB,
568                       color_edit);
569   gtk_object_set_data(GTK_OBJECT (color_delete), COLOR_FILTERS_CL,
570                       color_filters);
571   gtk_signal_connect (GTK_OBJECT (color_delete), "clicked",
572                       GTK_SIGNAL_FUNC (color_delete_cb),
573                       filter);
574   gtk_signal_connect (GTK_OBJECT (color_save), "clicked",
575                       GTK_SIGNAL_FUNC (color_save_cb),
576                       filter);
577   gtk_signal_connect (GTK_OBJECT (color_ok), "clicked",
578                       GTK_SIGNAL_FUNC (color_ok_cb),
579                       NULL);
580   gtk_signal_connect (GTK_OBJECT (color_apply), "clicked",
581                       GTK_SIGNAL_FUNC (color_apply_cb),
582                       filter);
583   gtk_signal_connect (GTK_OBJECT (color_cancel), "clicked",
584                       GTK_SIGNAL_FUNC (color_cancel_cb),
585                       NULL);
586
587   gtk_widget_grab_focus (color_filters);
588   gtk_object_set_data (GTK_OBJECT (color_win), "tooltips", tooltips);
589   gtk_widget_show (color_win);
590
591   return color_win;
592 }
593
594 static void
595 add_filter_to_clist(gpointer filter_arg, gpointer clist_arg)
596 {
597   color_filter_t *colorf = filter_arg;
598   GtkWidget *color_filters = clist_arg;
599   gchar *data[2];
600   gint row;
601
602   data[0] = colorf->filter_name;
603   data[1] = colorf->filter_text;
604   row = gtk_clist_append(GTK_CLIST(color_filters), data);
605   gtk_clist_set_row_data(GTK_CLIST(color_filters), row, colorf);
606   gtk_clist_set_foreground(GTK_CLIST(color_filters), row, &colorf->fg_color);
607   gtk_clist_set_background(GTK_CLIST(color_filters), row, &colorf->bg_color);
608 }
609
610 /* Move the selected filter up in the list */
611 static void
612 color_filter_up_cb                     (GtkButton       *button,
613                                         gpointer         user_data)
614 {
615   colfilter *filter;
616   gint filter_number;
617   GtkWidget *color_filters;
618   color_filter_t *colorf;
619
620   filter = (colfilter *)user_data;
621   filter_number = filter->row_selected;
622
623   /* If it is filter number 0, it cannot be moved, as it's already
624      at the top of the filter.
625      If there's only one filter in the list, it cannot be moved,
626      as there's no place to move it. */
627   if (filter_number != 0 && filter->num_of_filters >= 2) {
628         color_filters = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(button),
629                       COLOR_FILTERS_CL);
630         colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters),
631            filter_number);
632         gtk_clist_swap_rows(GTK_CLIST(color_filters), filter_number,
633                         filter_number-1);
634         filter_list = g_slist_remove(filter_list, colorf);
635         filter_list = g_slist_insert(filter_list, colorf, filter_number-1);
636         filter->row_selected--;
637   }
638 }
639
640 /* Move the selected filter down in the list */
641 static void
642 color_filter_down_cb                   (GtkButton       *button,
643                                         gpointer         user_data)
644 {
645   colfilter *filter;
646   gint filter_number;
647   GtkWidget *color_filters;
648   color_filter_t *colorf;
649
650   filter = (colfilter *)user_data;
651   filter_number = filter->row_selected;
652
653   /* If it is the last filter in the list, it cannot be moved, as it's
654      already at the bottom of the filter.
655      If there's only one filter in the list, it cannot be moved,
656      as there's no place to move it. */
657   if (filter_number != filter->num_of_filters-1
658     && filter->num_of_filters >= 2) {
659         color_filters = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(button),
660                       COLOR_FILTERS_CL);
661         colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters),
662            filter_number);
663         gtk_clist_swap_rows(GTK_CLIST(color_filters), filter_number+1,
664                         filter_number);
665         filter_list = g_slist_remove(filter_list, colorf);
666         filter_list = g_slist_insert(filter_list, colorf, filter_number+1);
667         filter->row_selected++;
668   }
669 }
670
671 /* Set selected row in cf */
672 static void
673 remember_selected_row                 (GtkCList        *clist,
674                                         gint             row,
675                                         gint             column,
676                                         GdkEvent        *event,
677                                         gpointer         user_data)
678 {
679   colfilter *filter = (colfilter *)user_data;
680
681   filter->row_selected = row;
682 }
683
684 /* Called when the dialog box is being destroyed; destroy any edit
685    dialogs opened from this dialog, and null out the pointer to this
686    dialog. */
687 static void
688 color_destroy_cb                       (GtkButton       *button,
689                                         gpointer         user_data)
690 {
691   /* Destroy any edit dialogs we have open. */
692   g_slist_foreach(filter_list, destroy_edit_dialog_cb, NULL);
693
694   colorize_win = NULL;
695 }
696
697 static void
698 destroy_edit_dialog_cb(gpointer filter_arg, gpointer dummy)
699 {
700   color_filter_t *colorf = (color_filter_t *)filter_arg;
701
702   if (colorf->edit_dialog != NULL)
703     gtk_widget_destroy(colorf->edit_dialog);
704 }
705
706 /* XXX - we don't forbid having more than one "Edit color filter" dialog
707    open, so these shouldn't be static. */
708 static GtkWidget *filt_name_entry;
709 static GtkWidget *filt_text_entry;
710
711 /* Create a new filter in the list, and pop up an "Edit color filter"
712    dialog box to edit it. */
713 static void
714 color_new_cb                          (GtkButton       *button,
715                                         gpointer         user_data)
716 {
717   colfilter *filter;
718   color_filter_t *colorf;
719   GtkWidget *color_filters;
720   gchar *data[2];
721   gint row;
722   GtkWidget *color_edit;
723
724   filter = (colfilter *)user_data;
725   colorf = new_color_filter(filter, "name", "filter"); /* Adds at end! */
726
727   color_filters = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(button),
728                       COLOR_FILTERS_CL);
729   data[0] = colorf->filter_name;
730   data[1] = colorf->filter_text;
731   row = gtk_clist_append(GTK_CLIST(color_filters), data);
732   gtk_clist_set_row_data(GTK_CLIST(color_filters), row, colorf);
733
734   /* A row has been added, so we can edit it. */
735   color_edit = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(button),
736                                         COLOR_EDIT_LB);
737   gtk_widget_set_sensitive (color_edit, TRUE);
738
739   /* select the new (last) row */
740   filter->row_selected = filter->num_of_filters;
741   filter->num_of_filters++;
742   gtk_clist_select_row(GTK_CLIST(color_filters), filter->row_selected, -1);
743   edit_color_filter_dialog_new(filter, color_filters, &filt_name_entry,
744                                 &filt_text_entry);
745 }
746
747 /* Pop up an "Edit color filter" dialog box to edit an existing filter. */
748 static void
749 color_edit_cb                        (GtkButton       *button,
750                                       gpointer         user_data)
751 {
752   colfilter *filter;
753   GtkWidget *color_filters;
754
755   filter = (colfilter *)user_data;
756   color_filters = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(button),
757                       COLOR_FILTERS_CL);
758   if(filter->row_selected == -1){
759         /* select the first row */
760         filter->row_selected = 0;
761         gtk_clist_select_row(GTK_CLIST(color_filters), filter->row_selected,
762                                 -1);
763   }
764   edit_color_filter_dialog_new(filter, color_filters, &filt_name_entry,
765                                 &filt_text_entry);
766 }
767
768 /* Delete a color from the list. */
769 static void
770 color_delete_cb(GtkWidget *widget, gpointer user_data)
771 {
772   colfilter *filter;
773   GtkWidget *color_filters;
774   color_filter_t *colorf;
775   GtkWidget *color_edit;
776
777   filter = (colfilter *)user_data;
778   if(filter->row_selected != -1){
779         color_filters = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget),
780                       COLOR_FILTERS_CL);
781         colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters),
782            filter->row_selected);
783
784         /* Remove this color filter from the CList displaying the
785            color filters. */
786         gtk_clist_remove(GTK_CLIST(color_filters), filter->row_selected);
787
788         /* Destroy any "Edit color filter" dialog boxes editing it. */
789         if (colorf->edit_dialog != NULL)
790                 gtk_widget_destroy(colorf->edit_dialog);
791
792         /* Remove the color filter from the list of color filters. */
793         delete_color_filter(colorf);
794         filter->num_of_filters--;
795         if(!filter->num_of_filters){
796                 /* No filters any more, so none can be selected... */
797                 filter->row_selected = -1;
798                 color_edit =
799                     (GtkWidget *) gtk_object_get_data(GTK_OBJECT(widget),
800                       COLOR_EDIT_LB);
801
802                 /* ...and none can be edited. */
803                 gtk_widget_set_sensitive (color_edit, FALSE);
804         } else {
805                 filter->row_selected--;
806                 if(filter->row_selected < 0)
807                         filter->row_selected = 0;
808                 gtk_clist_select_row(GTK_CLIST(color_filters),
809                     filter->row_selected, 0);
810         }
811   }
812 }
813
814 /* Save color filters to the color filter file. */
815 static void
816 color_save_cb                          (GtkButton       *button,
817                                         gpointer         user_data)
818 {
819   colfilter *filter = (colfilter *)user_data;
820
821   if (!write_filters(filter))
822         simple_dialog(ESD_TYPE_WARN, NULL, "Could not open filter file: %s",
823             strerror(errno));
824
825 }
826
827 /* Exit dialog and apply new list of color filters to the capture. */
828 static void
829 color_ok_cb                            (GtkButton       *button,
830                                         gpointer         user_data)
831 {
832   /* colorize list */
833   colorize_packets(&cf);
834
835   /* Destroy the dialog box. */
836   gtk_widget_destroy(colorize_win);
837 }
838
839 /* Exit dialog without colorizing packets with the new list.
840    XXX - should really undo any changes to the list.... */
841 static void
842 color_cancel_cb                        (GtkWidget       *widget,
843                                         gpointer         user_data)
844 {
845   /* Destroy the dialog box. */
846   gtk_widget_destroy(colorize_win);
847 }
848
849 /* Apply new list of color filters to the capture. */
850 static void
851 color_apply_cb                         (GtkButton       *button,
852                                         gpointer         user_data)
853 {
854   colorize_packets(&cf);
855 }
856
857 /* Create an "Edit color filter" dialog for a given color filter, and
858    associate it with that color filter. */
859 static void
860 edit_color_filter_dialog_new (colfilter *filter,
861         GtkWidget *color_filters,
862         GtkWidget **colorize_filter_name,
863         GtkWidget **colorize_filter_text)
864 {
865   color_filter_t *colorf;
866   GtkWidget *edit_dialog;
867   GtkWidget *vbox3;
868   GtkWidget *hbox6;
869   GtkWidget *color_filter_name;
870   GtkWidget *hbox7;
871   GtkWidget *color_filter_text;
872   GtkWidget *hbox5;
873   GtkWidget *colorize_filter_fg;
874   GtkWidget *colorize_filter_bg;
875   GtkWidget *hbox4;
876   GtkWidget *edit_color_filter_ok;
877   GtkWidget *edit_color_filter_cancel;
878   GtkTooltips *tooltips;
879   GtkStyle  *style;
880
881   colorf = gtk_clist_get_row_data(GTK_CLIST(color_filters),
882            filter->row_selected);
883   if (colorf->edit_dialog != NULL) {
884     /* There's already an edit box open for this filter; reactivate it. */
885     reactivate_window(colorf->edit_dialog);
886     return;
887   }
888
889   tooltips = gtk_tooltips_new ();
890
891   edit_dialog = gtk_window_new (GTK_WINDOW_DIALOG);
892   gtk_object_set_data (GTK_OBJECT (edit_dialog), "edit_dialog", edit_dialog);
893   gtk_window_set_title (GTK_WINDOW (edit_dialog), ("Edit color filter"));
894   colorf->edit_dialog = edit_dialog;
895
896   vbox3 = gtk_vbox_new (FALSE, 0);
897   gtk_widget_ref (vbox3);
898   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "vbox3", vbox3,
899                             (GtkDestroyNotify) gtk_widget_unref);
900   gtk_widget_show (vbox3);
901   gtk_container_add (GTK_CONTAINER (edit_dialog), vbox3);
902
903   hbox6 = gtk_hbox_new (FALSE, 0);
904   gtk_widget_ref (hbox6);
905   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "hbox6", hbox6,
906                             (GtkDestroyNotify) gtk_widget_unref);
907   gtk_widget_show (hbox6);
908   gtk_box_pack_start (GTK_BOX (vbox3), hbox6, TRUE, FALSE, 5);
909
910   color_filter_name = gtk_label_new (("Name: "));
911   gtk_widget_ref (color_filter_name);
912   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "color_filter_name", color_filter_name,
913                             (GtkDestroyNotify) gtk_widget_unref);
914   gtk_widget_show (color_filter_name);
915   gtk_box_pack_start (GTK_BOX (hbox6), color_filter_name, FALSE, FALSE, 0);
916
917   *colorize_filter_name = gtk_entry_new ();
918   gtk_widget_ref (*colorize_filter_name);
919   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "*colorize_filter_name", *colorize_filter_name,
920                             (GtkDestroyNotify) gtk_widget_unref);
921   gtk_entry_set_text(GTK_ENTRY(*colorize_filter_name), colorf->filter_name);
922
923   style = gtk_style_copy(gtk_widget_get_style(*colorize_filter_name));
924   style->base[GTK_STATE_NORMAL] = colorf->bg_color;
925   style->fg[GTK_STATE_NORMAL]   = colorf->fg_color;
926   gtk_widget_set_style(*colorize_filter_name, style);
927
928   gtk_widget_show (*colorize_filter_name);
929   gtk_box_pack_start (GTK_BOX (hbox6), *colorize_filter_name, TRUE, TRUE, 0);
930   gtk_tooltips_set_tip (tooltips, *colorize_filter_name, ("This is the editable name of the filter. (No @ characters allowed.)"), NULL);
931
932   hbox7 = gtk_hbox_new (FALSE, 0);
933   gtk_widget_ref (hbox7);
934   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "hbox7", hbox7,
935                             (GtkDestroyNotify) gtk_widget_unref);
936   gtk_widget_show (hbox7);
937   gtk_box_pack_start (GTK_BOX (vbox3), hbox7, TRUE, FALSE, 5);
938
939   color_filter_text = gtk_label_new (("Filter text:"));
940   gtk_widget_ref (color_filter_text);
941   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "color_filter_text", color_filter_text,
942                             (GtkDestroyNotify) gtk_widget_unref);
943   gtk_widget_show (color_filter_text);
944   gtk_box_pack_start (GTK_BOX (hbox7), color_filter_text, FALSE, FALSE, 0);
945
946   *colorize_filter_text = gtk_entry_new ();
947   gtk_widget_ref (*colorize_filter_text);
948   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "*colorize_filter_text", *colorize_filter_text,
949                             (GtkDestroyNotify) gtk_widget_unref);
950   gtk_entry_set_text(GTK_ENTRY(*colorize_filter_text), colorf->filter_text);
951 #if 0
952   style = gtk_style_copy(gtk_widget_get_style(*colorize_filter_text));
953   style->base[GTK_STATE_NORMAL] = colorf->bg_color;
954   style->fg[GTK_STATE_NORMAL]   = colorf->fg_color;
955 #endif
956   gtk_widget_set_style(*colorize_filter_text, style);
957   gtk_widget_show (*colorize_filter_text);
958   gtk_box_pack_start (GTK_BOX (hbox7), *colorize_filter_text, TRUE, TRUE, 0);
959   gtk_tooltips_set_tip (tooltips, *colorize_filter_text, ("This is the editable text of the filter"), NULL);
960
961   hbox5 = gtk_hbox_new (FALSE, 0);
962   gtk_widget_ref (hbox5);
963   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "hbox5", hbox5,
964                             (GtkDestroyNotify) gtk_widget_unref);
965   gtk_widget_show (hbox5);
966   gtk_box_pack_start (GTK_BOX (vbox3), hbox5, FALSE, FALSE, 5);
967   gtk_widget_set_usize (hbox5, -2, 60);
968
969   colorize_filter_fg = gtk_button_new_with_label (("Choose \nforeground\ncolor"));
970   gtk_widget_ref (colorize_filter_fg);
971   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "colorize_filter_fg", colorize_filter_fg,
972                             (GtkDestroyNotify) gtk_widget_unref);
973   gtk_widget_show (colorize_filter_fg);
974   gtk_box_pack_start (GTK_BOX (hbox5), colorize_filter_fg, TRUE, FALSE, 0);
975   gtk_tooltips_set_tip (tooltips, colorize_filter_fg, ("Select color for data display"), NULL);
976
977   colorize_filter_bg = gtk_button_new_with_label (("Choose\nbackground\ncolor"));
978   gtk_widget_ref (colorize_filter_bg);
979   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "colorize_filter_bg", colorize_filter_bg,
980                             (GtkDestroyNotify) gtk_widget_unref);
981   gtk_widget_show (colorize_filter_bg);
982   gtk_box_pack_start (GTK_BOX (hbox5), colorize_filter_bg, TRUE, FALSE, 0);
983   gtk_tooltips_set_tip (tooltips, colorize_filter_bg, ("Select color for data display"), NULL);
984
985   hbox4 = gtk_hbox_new (FALSE, 0);
986   gtk_widget_ref (hbox4);
987   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "hbox4", hbox4,
988                             (GtkDestroyNotify) gtk_widget_unref);
989   gtk_widget_show (hbox4);
990   gtk_box_pack_start (GTK_BOX (vbox3), hbox4, TRUE, FALSE, 5);
991   gtk_widget_set_usize (hbox4, -2, 40);
992
993   edit_color_filter_ok = gtk_button_new_with_label (("OK"));
994   gtk_widget_ref (edit_color_filter_ok);
995   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "edit_color_filter_ok", edit_color_filter_ok,
996                             (GtkDestroyNotify) gtk_widget_unref);
997   gtk_widget_set_usize (edit_color_filter_ok, 50, 30);
998   gtk_widget_show (edit_color_filter_ok);
999   gtk_box_pack_start (GTK_BOX (hbox4), edit_color_filter_ok, TRUE, FALSE, 0);
1000   gtk_tooltips_set_tip (tooltips, edit_color_filter_ok, ("Accept filter color change"), NULL);
1001
1002   edit_color_filter_cancel = gtk_button_new_with_label (("Cancel"));
1003   gtk_widget_ref (edit_color_filter_cancel);
1004   gtk_object_set_data_full (GTK_OBJECT (edit_dialog), "edit_color_filter_cancel", edit_color_filter_cancel,
1005                             (GtkDestroyNotify) gtk_widget_unref);
1006   gtk_widget_set_usize (edit_color_filter_cancel, 50, 30);
1007   gtk_widget_show (edit_color_filter_cancel);
1008   gtk_box_pack_start (GTK_BOX (hbox4), edit_color_filter_cancel, TRUE, FALSE, 0);
1009   gtk_tooltips_set_tip (tooltips, edit_color_filter_cancel, ("Reject filter color change"), NULL);
1010   gtk_object_set_data(GTK_OBJECT (edit_dialog), COLOR_FILTER,
1011                       colorf);
1012   gtk_signal_connect (GTK_OBJECT (edit_dialog), "destroy",
1013                       GTK_SIGNAL_FUNC (edit_color_filter_destroy_cb),
1014                       NULL);
1015   gtk_object_set_data(GTK_OBJECT (colorize_filter_fg), COLOR_FILTER,
1016                       colorf);
1017   gtk_signal_connect (GTK_OBJECT (colorize_filter_fg), "clicked",
1018                       GTK_SIGNAL_FUNC (edit_color_filter_fg_cb),
1019                       filter);
1020   gtk_object_set_data(GTK_OBJECT (colorize_filter_bg), COLOR_FILTER,
1021                       colorf);
1022   gtk_signal_connect (GTK_OBJECT (colorize_filter_bg), "clicked",
1023                       GTK_SIGNAL_FUNC (edit_color_filter_bg_cb),
1024                       filter);
1025   gtk_object_set_data(GTK_OBJECT (edit_color_filter_ok), COLOR_FILTERS_CL,
1026                       color_filters);
1027   gtk_object_set_data(GTK_OBJECT (edit_color_filter_ok), COLOR_FILTER,
1028                       colorf);
1029   gtk_signal_connect (GTK_OBJECT (edit_color_filter_ok), "clicked",
1030                       GTK_SIGNAL_FUNC (edit_color_filter_ok_cb),
1031                       edit_dialog);
1032   gtk_signal_connect (GTK_OBJECT (edit_color_filter_cancel), "clicked",
1033                       GTK_SIGNAL_FUNC (edit_color_filter_cancel_cb),
1034                       edit_dialog);
1035
1036   gtk_object_set_data (GTK_OBJECT (edit_dialog), "tooltips", tooltips);
1037   gtk_widget_show (edit_dialog);
1038 }
1039
1040 /* Called when the dialog box is being destroyed; destroy any color
1041    selection dialogs opened from this dialog, and null out the pointer
1042    to this dialog. */
1043 static void
1044 edit_color_filter_destroy_cb           (GtkObject       *object,
1045                                         gpointer         user_data)
1046 {
1047   color_filter_t *colorf;
1048   GtkWidget *color_sel;
1049
1050   colorf = (color_filter_t *) gtk_object_get_data(GTK_OBJECT(object),
1051                       COLOR_FILTER);
1052
1053   colorf->edit_dialog = NULL;
1054
1055   /* Destroy any color selection dialogs this dialog had open. */
1056   color_sel = (GtkWidget *) gtk_object_get_data(object, COLOR_SELECTION_FG);
1057   if (color_sel != NULL)
1058     gtk_widget_destroy(color_sel);
1059   color_sel = (GtkWidget *) gtk_object_get_data(object, COLOR_SELECTION_BG);
1060   if (color_sel != NULL)
1061     gtk_widget_destroy(color_sel);
1062 }
1063
1064 /* Pop up a color selection box to choose the foreground color. */
1065 static void
1066 edit_color_filter_fg_cb                (GtkButton       *button,
1067                                         gpointer         user_data)
1068 {
1069   colfilter *filter;
1070   color_filter_t *colorf;
1071   GtkWidget *color_selection_fg;
1072
1073   filter = (colfilter *)user_data;
1074   colorf = (color_filter_t *) gtk_object_get_data(GTK_OBJECT(button),
1075                       COLOR_FILTER);
1076   /* Do we already have one open for this dialog? */
1077   color_selection_fg = gtk_object_get_data(GTK_OBJECT (colorf->edit_dialog),
1078       COLOR_SELECTION_FG);
1079   if (color_selection_fg != NULL) {
1080     /* Yes.  Just reactivate it. */
1081     reactivate_window(color_selection_fg);
1082   } else {
1083     /* No.  Create a new color selection box, and associate it with
1084        this dialog. */
1085     color_selection_fg = color_sel_win_new(colorf, FALSE);
1086     gtk_object_set_data(GTK_OBJECT (colorf->edit_dialog), COLOR_SELECTION_FG,
1087                       color_selection_fg);
1088     gtk_object_set_data(GTK_OBJECT (color_selection_fg),
1089                 COLOR_SELECTION_PARENT, colorf->edit_dialog);
1090   }
1091 }
1092
1093 /* Pop up a color selection box to choose the background color. */
1094 static void
1095 edit_color_filter_bg_cb                (GtkButton       *button,
1096                                         gpointer         user_data)
1097 {
1098   colfilter *filter;
1099   color_filter_t *colorf;
1100   GtkWidget *color_selection_bg;
1101
1102   filter = (colfilter *)user_data;
1103   colorf = (color_filter_t *) gtk_object_get_data(GTK_OBJECT(button),
1104                       COLOR_FILTER);
1105
1106   /* Do we already have one open for this dialog? */
1107   color_selection_bg = gtk_object_get_data(GTK_OBJECT (colorf->edit_dialog),
1108       COLOR_SELECTION_BG);
1109   if (color_selection_bg != NULL) {
1110     /* Yes.  Just reactivate it. */
1111     reactivate_window(color_selection_bg);
1112   } else {
1113     /* No.  Create a new color selection box, and associate it with
1114        this dialog. */
1115     color_selection_bg = color_sel_win_new(colorf, TRUE);
1116     gtk_object_set_data(GTK_OBJECT (colorf->edit_dialog), COLOR_SELECTION_BG,
1117                       color_selection_bg);
1118     gtk_object_set_data(GTK_OBJECT (color_selection_bg),
1119                 COLOR_SELECTION_PARENT, colorf->edit_dialog);
1120   }
1121 }
1122
1123 /* accept color (and potential content) change */
1124 static void
1125 edit_color_filter_ok_cb                (GtkButton       *button,
1126                                         gpointer         user_data)
1127 {
1128   GtkWidget *dialog;
1129   GtkStyle *style;
1130   GdkColor new_fg_color;
1131   GdkColor new_bg_color;
1132   gchar *filter_name;
1133   gchar *filter_text;
1134   color_filter_t *colorf;
1135   dfilter *compiled_filter;
1136   GtkWidget *color_filters;
1137
1138   dialog = (GtkWidget *)user_data;
1139
1140   style = gtk_widget_get_style(filt_name_entry);
1141   new_bg_color = style->base[GTK_STATE_NORMAL];
1142   new_fg_color = style->fg[GTK_STATE_NORMAL];
1143
1144   filter_name = g_strdup(gtk_entry_get_text(GTK_ENTRY(filt_name_entry)));
1145   filter_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(filt_text_entry)));
1146
1147   if(strchr(filter_name,'@') || strchr(filter_text,'@')){
1148         simple_dialog(ESD_TYPE_WARN,NULL, "Filter names and strings must not"
1149           " use the '@' character. Filter unchanged.");
1150         g_free(filter_name);
1151         g_free(filter_text);
1152         return;
1153   }
1154
1155   if(dfilter_compile(filter_text, &compiled_filter) != 0 ){
1156         simple_dialog(ESD_TYPE_WARN, NULL, "Filter \"%s\" did not compile correctly.\n"
1157                 " Please try again. Filter unchanged.\n%s\n", filter_name,
1158                 dfilter_error_msg);
1159   } else {
1160         color_filters = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(button),
1161                       COLOR_FILTERS_CL);
1162         colorf = (color_filter_t *) gtk_object_get_data(GTK_OBJECT(button),
1163                       COLOR_FILTER);
1164
1165         if (colorf->filter_name != NULL)
1166             g_free(colorf->filter_name);
1167         colorf->filter_name = filter_name;
1168         if (colorf->filter_text != NULL)
1169             g_free(colorf->filter_text);
1170         colorf->filter_text = filter_text;
1171         colorf->fg_color = new_fg_color;
1172         colorf->bg_color = new_bg_color;
1173         gtk_clist_set_foreground(GTK_CLIST(color_filters),
1174             cf.colors->row_selected, &new_fg_color);
1175         gtk_clist_set_background(GTK_CLIST(color_filters),
1176             cf.colors->row_selected, &new_bg_color);
1177         if(colorf->c_colorfilter != NULL)
1178             dfilter_destroy(colorf->c_colorfilter);
1179         colorf->c_colorfilter = compiled_filter;
1180         /* gtk_clist_set_text frees old text (if any) and allocates new space */
1181         gtk_clist_set_text(GTK_CLIST(color_filters),
1182                 cf.colors->row_selected, 0, filter_name);
1183         gtk_clist_set_text(GTK_CLIST(color_filters),
1184                 cf.colors->row_selected, 1, filter_text);
1185
1186         /* Destroy the dialog box. */
1187         gtk_widget_destroy(dialog);
1188   }
1189 }
1190
1191 /* Exit dialog and do not process list */
1192 static void
1193 edit_color_filter_cancel_cb            (GtkObject       *object,
1194                                         gpointer         user_data)
1195 {
1196   GtkWidget *dialog;
1197
1198   dialog = (GtkWidget *)user_data;
1199
1200   /* Destroy the dialog box. */
1201   gtk_widget_destroy(dialog);
1202 }
1203
1204 static GtkWidget*
1205 color_sel_win_new(color_filter_t *colorf, gboolean is_bg)
1206 {
1207   gint title_len;
1208   gchar *title;
1209   static const gchar fg_title_format[] = "Choose foreground color for \"%s\"";
1210   static const gchar bg_title_format[] = "Choose background color for \"%s\"";
1211   GtkWidget *color_sel_win;
1212   GdkColor *color;
1213   GtkWidget *color_sel_ok;
1214   GtkWidget *color_sel_cancel;
1215   GtkWidget *color_sel_help;
1216
1217   if (is_bg) {
1218     color = &colorf->bg_color;
1219     title_len = strlen(bg_title_format) + strlen(colorf->filter_name);
1220     title = g_malloc(title_len + 1);
1221     sprintf(title, bg_title_format, colorf->filter_name);
1222   } else {
1223     color = &colorf->fg_color;
1224     title_len = strlen(fg_title_format) + strlen(colorf->filter_name);
1225     title = g_malloc(title_len + 1);
1226     sprintf(title, fg_title_format, colorf->filter_name);
1227   }
1228   color_sel_win = gtk_color_selection_dialog_new(title);
1229   g_free(title);
1230   gtk_object_set_data (GTK_OBJECT (color_sel_win), "color_sel_win", color_sel_win);
1231   gtk_container_set_border_width (GTK_CONTAINER (color_sel_win), 10);
1232
1233   if (color != NULL) {
1234     gdouble cols[3];
1235
1236     cols[0] = (gdouble)color->red / 65536.0;
1237     cols[1] = (gdouble)color->green / 65536.0;
1238     cols[2] = (gdouble)color->blue / 65536.0;
1239
1240     gtk_color_selection_set_color(
1241                     GTK_COLOR_SELECTION(
1242                             GTK_COLOR_SELECTION_DIALOG(color_sel_win)->colorsel), cols);
1243   }
1244
1245   color_sel_ok = GTK_COLOR_SELECTION_DIALOG (color_sel_win)->ok_button;
1246   gtk_object_set_data (GTK_OBJECT (color_sel_win), "color_sel_ok", color_sel_ok);
1247   gtk_widget_show (color_sel_ok);
1248   GTK_WIDGET_SET_FLAGS (color_sel_ok, GTK_CAN_DEFAULT);
1249
1250   color_sel_cancel = GTK_COLOR_SELECTION_DIALOG (color_sel_win)->cancel_button;
1251   gtk_object_set_data (GTK_OBJECT (color_sel_win), "color_sel_cancel", color_sel_cancel);
1252   gtk_widget_show (color_sel_cancel);
1253   GTK_WIDGET_SET_FLAGS (color_sel_cancel, GTK_CAN_DEFAULT);
1254
1255
1256   color_sel_help = GTK_COLOR_SELECTION_DIALOG (color_sel_win)->help_button;
1257   gtk_object_set_data (GTK_OBJECT (color_sel_win), "color_sel_help", color_sel_help);
1258   gtk_widget_show (color_sel_help);
1259
1260
1261   GTK_WIDGET_SET_FLAGS (color_sel_help, GTK_CAN_DEFAULT);
1262   gtk_signal_connect (GTK_OBJECT (color_sel_win), "destroy",
1263                       GTK_SIGNAL_FUNC (color_sel_cancel_cb),
1264                       color_sel_win);
1265
1266   gtk_signal_connect (GTK_OBJECT (color_sel_ok), "clicked",
1267                       GTK_SIGNAL_FUNC (color_sel_ok_cb),
1268                       color_sel_win);
1269   gtk_signal_connect (GTK_OBJECT (color_sel_cancel), "clicked",
1270                       GTK_SIGNAL_FUNC (color_sel_cancel_cb),
1271                       color_sel_win);
1272
1273   gtk_widget_show(color_sel_win);
1274   return color_sel_win;
1275 }
1276
1277 static void
1278 color_sel_win_destroy(GtkWidget *sel_win)
1279 {
1280   GtkWidget *parent;
1281   GtkWidget *color_selection_fg, *color_selection_bg;
1282
1283   /* Find the "Edit color filter" dialog box with which this is associated. */
1284   parent = (GtkWidget *)gtk_object_get_data(GTK_OBJECT (sel_win),
1285       COLOR_SELECTION_PARENT);
1286
1287   /* Find that dialog box's foreground and background color selection
1288      boxes, if any. */
1289   color_selection_fg = gtk_object_get_data(GTK_OBJECT (parent),
1290       COLOR_SELECTION_FG);
1291   color_selection_bg = gtk_object_get_data(GTK_OBJECT (parent),
1292       COLOR_SELECTION_BG);
1293
1294   if (sel_win == color_selection_fg) {
1295     /* This was its foreground color selection box; it isn't, anymore. */
1296     gtk_object_set_data(GTK_OBJECT (parent), COLOR_SELECTION_FG, NULL);
1297   }
1298   if (sel_win == color_selection_bg) {
1299     /* This was its background color selection box; it isn't, anymore. */
1300     gtk_object_set_data(GTK_OBJECT (parent), COLOR_SELECTION_BG, NULL);
1301   }
1302
1303   /* Now destroy it. */
1304   gtk_widget_destroy(sel_win);
1305 }
1306
1307 /* Retrieve selected color */
1308 static void
1309 color_sel_ok_cb                        (GtkButton       *button,
1310                                         gpointer         user_data)
1311 {
1312   GdkColor new_color; /* Color from color selection dialog */
1313   gdouble new_colors[3];
1314   GtkWidget *color_dialog;
1315   GtkStyle  *style;
1316   GtkWidget *parent;
1317   GtkWidget *color_selection_fg, *color_selection_bg;
1318   gboolean is_bg;
1319
1320   color_dialog = (GtkWidget *)user_data;
1321
1322   gtk_color_selection_get_color(GTK_COLOR_SELECTION(
1323    GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel), new_colors);
1324
1325   new_color.red   = (guint16)(new_colors[0]*65535.0);
1326   new_color.green = (guint16)(new_colors[1]*65535.0);
1327   new_color.blue  = (guint16)(new_colors[2]*65535.0);
1328
1329   if ( ! get_color(&new_color) ){
1330         simple_dialog(ESD_TYPE_WARN, NULL, "Could not allocate color.  Try again.");
1331   } else {
1332         /* Find the "Edit color filter" dialog box with which this is
1333            associated. */
1334         parent = (GtkWidget *)gtk_object_get_data(GTK_OBJECT (color_dialog),
1335               COLOR_SELECTION_PARENT);
1336
1337         /* Find that dialog box's foreground and background color selection
1338            boxes, if any. */
1339         color_selection_fg = gtk_object_get_data(GTK_OBJECT (parent),
1340               COLOR_SELECTION_FG);
1341         color_selection_bg = gtk_object_get_data(GTK_OBJECT (parent),
1342               COLOR_SELECTION_BG);
1343         is_bg = (color_dialog == color_selection_bg);
1344
1345         color_sel_win_destroy(color_dialog);
1346
1347         /* now apply the change to the fore/background */
1348         
1349         style = gtk_style_copy(gtk_widget_get_style(filt_name_entry));
1350         if (is_bg)
1351           style->base[GTK_STATE_NORMAL] = new_color;
1352         else
1353           style->fg[GTK_STATE_NORMAL] = new_color;
1354         gtk_widget_set_style(filt_name_entry, style);
1355         gtk_widget_set_style(filt_text_entry, style);   
1356   }
1357 }
1358
1359 /* Don't choose the selected color as the foreground or background
1360    color for the filter. */
1361 static void
1362 color_sel_cancel_cb                    (GtkObject       *object,
1363                                         gpointer         user_data)
1364 {
1365   GtkWidget *color_dialog;
1366   color_dialog = (GtkWidget *)user_data;
1367   /* nothing to change here.  Just get rid of the dialog box. */
1368
1369   color_sel_win_destroy(color_dialog);
1370 }
1371
1372 static gboolean
1373 get_color (GdkColor *new_color)
1374 {
1375     GdkVisual *pv;
1376
1377     if (!our_cmap) {
1378         if ( !gdk_colormap_alloc_color (sys_cmap, new_color, FALSE, TRUE)) {
1379             pv = gdk_visual_get_best();
1380             if ( !(our_cmap = gdk_colormap_new(pv, TRUE)))
1381                 simple_dialog(ESD_TYPE_WARN, NULL, "Could not create new colormap");
1382         } else
1383             return (TRUE);
1384     }
1385     return ( gdk_colormap_alloc_color ( our_cmap, new_color, FALSE, TRUE) );
1386 }