Make sure that plugin tap listeners get registered before the non-plugin tap listeners
[obnox/wireshark/wip.git] / gtk / stats_tree_stat.c
1 /* stats_tree_stat.c
2  * GTK Tap implementation of stats_tree
3  * 2005, Luis E. G. Ontanon
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
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 /*
27  TODO:
28
29  - GTK1 something better than just a textbox
30  
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <string.h>
38 #include <gtk/gtk.h>
39
40 #include <epan/stats_tree_priv.h>
41
42 #include "simple_dialog.h"
43 #include "globals.h"
44 #include "tap_menu.h"
45 #include "ui_util.h"
46 #include "dlg_utils.h"
47 #include "compat_macros.h"
48 #include "tap_dfilter_dlg.h"
49 #include "../tap_dfilter_dlg.h"
50
51 struct _st_node_pres {
52 #if GTK_MAJOR_VERSION >= 2
53         GtkTreeIter*    iter;
54 #else
55         /* g_malloc(0) ??? */
56         void*           dummy;
57 #endif
58 };
59
60
61 struct _tree_pres {
62         tap_dfilter_dlg* stat_dlg;
63         GString*                text;
64         GtkWidget*              win;
65         
66 #if GTK_MAJOR_VERSION >= 2
67         GtkTreeStore*   store;
68         GtkWidget*              tree;
69 #else
70         GtkWidget*              textbox;
71 #endif
72 };
73
74 /* the columns of the tree pane */
75 enum _stat_tree_columns {
76         COUNT_COLUMN,
77         RATE_COLUMN,
78         TITLE_COLUMN,
79         PERCENT_COLUMN,
80         N_COLUMNS
81 };
82
83 /* used for converting numbers */
84 #define NUM_BUF_SIZE  32
85
86 /* creates the gtk representation for a stat_node
87  * node: the node
88  */
89 static void setup_gtk_node_pr(stat_node* node) {
90 #if GTK_MAJOR_VERSION >= 2
91         GtkTreeIter* parent =  NULL;
92 #endif
93         
94
95         node->pr = g_malloc(sizeof(st_node_pres));
96
97 #if GTK_MAJOR_VERSION >= 2
98         
99         if ( node->parent && node->parent->pr ) {
100                 parent = node->parent->pr->iter;
101         }
102         
103         if (node->st->pr->store) {
104                 node->pr->iter = g_malloc0(sizeof(GtkTreeIter));
105
106                 gtk_tree_store_append (node->st->pr->store, node->pr->iter, parent);
107                 gtk_tree_store_set(node->st->pr->store, node->pr->iter, TITLE_COLUMN, node->name, RATE_COLUMN, "", COUNT_COLUMN, "", -1);
108         }
109 #else
110         node->pr->dummy = NULL;
111         
112 #endif
113 }
114
115
116 #if GTK_MAJOR_VERSION >= 2
117 static void draw_gtk_node(stat_node* node) {
118         static gchar value[NUM_BUF_SIZE];
119         static gchar rate[NUM_BUF_SIZE];
120         static gchar percent[NUM_BUF_SIZE];
121         stat_node* child;
122         
123         get_strings_from_node(node, value, rate, percent);
124         
125         if (node->st->pr->store) {
126                 gtk_tree_store_set(node->st->pr->store, node->pr->iter,
127                                                    RATE_COLUMN, rate,
128                                                    COUNT_COLUMN, value,
129                                                    PERCENT_COLUMN, percent,
130                                                    -1);
131         }
132         
133         if (node->children) {
134                 for (child = node->children; child; child = child->next )
135                         draw_gtk_node(child);
136         }
137 }
138 #else
139 static void draw_gtk_node(stat_node* node _U_) {}
140 #endif
141
142 static void draw_gtk_tree( void *psp  ) {
143         stats_tree *st = psp;
144         stat_node* child;
145
146 #if GTK_MAJOR_VERSION >= 2
147
148         for (child = st->root.children; child; child = child->next ) {
149                 draw_gtk_node(child);
150         }
151 #else
152         GString* text = g_string_new("");
153         gchar* fmt;
154         
155         fmt = g_strdup_printf(" %%s%%-%us%%12s\t%%12s\t%%12s\n",stats_branch_max_name_len(&st->root,0));
156         g_string_sprintfa(text,fmt,"",st->name,"value","rate","percent");
157         g_free(fmt);
158         g_string_sprintfa(text,"-------------------------------------------------------------------\n");
159
160         
161         for (child = st->root.children; child; child = child->next ) {
162                 stat_branch_to_str(child,text,0);
163         }
164         
165         gtk_text_freeze(GTK_TEXT(st->pr->textbox));
166         gtk_text_set_point(GTK_TEXT(st->pr->textbox),0);
167         gtk_text_forward_delete(GTK_TEXT(st->pr->textbox),gtk_text_get_length(GTK_TEXT(st->pr->textbox)));
168         gtk_text_insert(GTK_TEXT(st->pr->textbox),NULL,
169                                         NULL,NULL,text->str,-1);
170         gtk_text_thaw(GTK_TEXT(st->pr->textbox));
171         
172         g_string_free(text,TRUE);
173 #endif  
174 }
175
176 void protect_thread_critical_region(void);
177 void unprotect_thread_critical_region(void);
178
179 static void free_gtk_tree(GtkWindow *win _U_, stats_tree *st)
180 {
181         
182         protect_thread_critical_region();
183         remove_tap_listener(st);
184         unprotect_thread_critical_region();
185         
186 #if GTK_MAJOR_VERSION >= 2
187         if (st->root.pr)
188                 st->root.pr->iter = NULL;
189 #endif
190 }
191
192
193 /* initializes the stats_tree window */
194 static void init_gtk_tree(char* optarg) {
195         guint8* abbr = get_st_abbr(optarg);
196         stats_tree* st = NULL;
197         guint8* title = NULL;
198         guint8* window_name = NULL;
199         GString* error_string;
200         GtkWidget *scr_win;
201         guint init_strlen;
202 #if GTK_MAJOR_VERSION >= 2
203         GtkTreeViewColumn* column;
204         GtkCellRenderer* renderer;
205 #endif
206         
207         if (abbr) {
208                 st = get_stats_tree_by_abbr(abbr);
209                 
210                 if (st != NULL) {
211                         init_strlen = strlen(st->pr->stat_dlg->init_string);
212                         
213                         if (strncmp (optarg, st->pr->stat_dlg->init_string, init_strlen) == 0){
214                                 if (init_strlen == strlen(optarg)) {
215                                         st->filter= "";
216                                 } else { 
217                                         st->filter=((guint8*)optarg)+init_strlen+1;
218                                 }
219                                 
220                         } else {
221                                 st->filter=NULL;
222                         }
223                 } else {
224                         g_error("no such stats_tree (%s) found in stats_tree registry",abbr);
225                 }
226                 g_free(abbr);
227                 
228         } else {
229                 g_error("could not obtain stats_tree abbr from optarg");                
230         }
231         
232         window_name = g_strdup_printf("%s Stats Tree", st->name);
233         
234         st->pr->win = window_new_with_geom(GTK_WINDOW_TOPLEVEL,window_name,window_name);
235         g_free(window_name);
236         
237         if(st->filter){
238                 title=g_strdup_printf("%s with filter: %s",st->name,st->filter);
239         } else {
240                 st->filter=NULL;
241                 title=g_strdup_printf("%s", st->name);
242         }
243         
244     gtk_window_set_title(GTK_WINDOW(st->pr->win), title);
245         g_free(title);
246
247         scr_win = scrolled_window_new(NULL, NULL);
248
249 #if GTK_MAJOR_VERSION >= 2
250         
251         st->pr->store = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
252                                                                         G_TYPE_STRING, G_TYPE_STRING);
253         
254         st->pr->tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (st->pr->store));
255         
256         gtk_container_add( GTK_CONTAINER(scr_win), st->pr->tree);
257         gtk_container_add( GTK_CONTAINER(st->pr->win), scr_win);
258         
259         /* the columns */
260         renderer = gtk_cell_renderer_text_new ();
261         column = gtk_tree_view_column_new_with_attributes ("What", renderer,
262                                                                                                            "text", TITLE_COLUMN,
263                                                                                                            NULL);
264         gtk_tree_view_column_set_resizable (column,TRUE);
265         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
266         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
267         
268         renderer = gtk_cell_renderer_text_new ();
269         column = gtk_tree_view_column_new_with_attributes ("count", renderer,
270                                                                                                            "text", COUNT_COLUMN,
271                                                                                                            NULL);
272         
273         gtk_tree_view_column_set_resizable (column,TRUE);
274         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
275         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
276         
277         renderer = gtk_cell_renderer_text_new ();
278         column = gtk_tree_view_column_new_with_attributes ("rate", renderer,
279                                                                                                            "text", RATE_COLUMN,
280                                                                                                            NULL);
281         gtk_tree_view_column_set_resizable (column,TRUE);
282         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
283         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
284         
285         renderer = gtk_cell_renderer_text_new ();
286         column = gtk_tree_view_column_new_with_attributes ("percent", renderer,
287                                                                                                            "text", PERCENT_COLUMN,
288                                                                                                            NULL);
289         gtk_tree_view_column_set_resizable(column,TRUE);
290         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
291         gtk_tree_view_append_column (GTK_TREE_VIEW (st->pr->tree), column);
292 #else
293         st->pr->textbox = GTK_TEXT(gtk_text_new(NULL,NULL));
294         gtk_text_set_editable(GTK_TEXT(st->pr->textbox),TRUE);
295         gtk_container_add( GTK_CONTAINER(scr_win), GTK_WIDGET(st->pr->textbox));
296         gtk_container_add( GTK_CONTAINER(st->pr->win), scr_win);
297 #endif
298         
299         error_string = register_tap_listener( st->tapname,
300                                                                                   st,
301                                                                                   st->filter,
302                                                                                   NULL,
303                                                                                   stats_tree_packet,
304                                                                                   draw_gtk_tree);
305         
306         if (error_string) {
307                 /* error, we failed to attach to the tap. clean up */
308                 simple_dialog( ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str );
309                 /* destroy_stat_tree_window(st); */
310                 g_error("stats_tree for: %s failed to attach to the tap: %s",st->name,error_string->str);
311                 g_string_free(error_string, TRUE);
312         }
313                 
314         SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "delete_event", window_delete_event_cb, NULL);
315         SIGNAL_CONNECT(GTK_WINDOW(st->pr->win), "destroy", free_gtk_tree, st);
316         
317         gtk_widget_show_all(st->pr->win);
318         window_present(st->pr->win);
319         
320 #if GTK_MAJOR_VERSION >= 2
321         gtk_tree_view_set_model(GTK_TREE_VIEW(st->pr->tree),GTK_TREE_MODEL(st->pr->store));
322 #endif
323         
324         if (st->filter) {
325                 reinit_stats_tree(st);
326         } else {
327                 st->init(st);
328         }
329
330         cf_retap_packets(&cfile);
331         
332 }
333
334
335 static void register_gtk_stats_tree_tap (gpointer k _U_, gpointer v, gpointer p _U_) {
336         stats_tree* st = v;
337         guint8* s;
338
339         s = g_strdup_printf("%s,tree",st->abbr);
340         
341         register_ethereal_tap(s, init_gtk_tree);
342         g_free(s);
343         
344         st->pr = g_malloc(sizeof(tree_pres));
345         st->pr->text = NULL;
346         st->pr->win = NULL;
347         
348 #if GTK_MAJOR_VERSION >= 2
349         st->pr->store = NULL;
350         st->pr->tree = NULL;
351 #else
352         st->pr->textbox = NULL;
353 #endif
354         
355         st->pr->stat_dlg = g_malloc(sizeof(tap_dfilter_dlg));
356         
357         st->pr->stat_dlg->win_title = g_strdup_printf("%s Packet Counter",st->name);
358         st->pr->stat_dlg->init_string = g_strdup_printf("%s,tree",st->abbr);
359         st->pr->stat_dlg->tap_init_cb = init_gtk_tree;
360         st->pr->stat_dlg->index = -1;
361         
362         register_tap_menu_item(st->name, REGISTER_TAP_GROUP_NONE,
363                                                    gtk_tap_dfilter_dlg_cb, NULL, NULL, st->pr->stat_dlg);
364 }
365
366 void
367 register_tap_listener_stats_tree_stat(void)
368 {       
369         stats_tree_presentation(register_gtk_stats_tree_tap,
370                                                         setup_gtk_node_pr, NULL,
371                                                         NULL,
372                                                         NULL, NULL, NULL, NULL, NULL, NULL);
373 }