2002-11-14 10:32:22 +00:00
|
|
|
/* io_stat.c
|
|
|
|
* io_stat 2002 Ronnie Sahlberg
|
|
|
|
*
|
2006-05-21 05:12:17 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2002-11-14 10:32:22 +00:00
|
|
|
* Copyright 1998 Gerald Combs
|
2008-08-05 17:33:14 +00:00
|
|
|
*
|
2002-11-14 10:32:22 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2008-08-05 17:33:14 +00:00
|
|
|
*
|
2002-11-14 10:32:22 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2008-08-05 17:33:14 +00:00
|
|
|
*
|
2002-11-14 10:32:22 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-06-28 22:56:06 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2002-11-14 10:32:22 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-09-20 01:48:30 +00:00
|
|
|
#include "config.h"
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2009-08-27 04:47:28 +00:00
|
|
|
#include <stdio.h>
|
2002-11-14 10:32:22 +00:00
|
|
|
#include <string.h>
|
2008-02-20 17:53:31 +00:00
|
|
|
#include <math.h>
|
2002-11-16 21:40:32 +00:00
|
|
|
#include <ctype.h>
|
2002-11-14 10:32:22 +00:00
|
|
|
#include <gtk/gtk.h>
|
2004-02-13 00:53:37 +00:00
|
|
|
|
|
|
|
#include <epan/epan_dissect.h>
|
|
|
|
#include <epan/packet_info.h>
|
2005-08-20 20:06:05 +00:00
|
|
|
#include <epan/stat_cmd_args.h>
|
2004-09-29 00:06:36 +00:00
|
|
|
#include <epan/tap.h>
|
2008-04-13 03:32:24 +00:00
|
|
|
#include <epan/strutil.h>
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
#include "../../stat_menu.h"
|
2012-01-16 01:07:52 +00:00
|
|
|
#include "ui/alert_box.h"
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
#include "ui/io_graph_item.h"
|
2012-01-16 01:07:52 +00:00
|
|
|
#include "ui/simple_dialog.h"
|
2008-04-13 03:32:24 +00:00
|
|
|
|
2012-01-15 21:59:11 +00:00
|
|
|
#include "ui/gtk/gtkglobals.h"
|
|
|
|
#include "ui/gtk/gui_utils.h"
|
|
|
|
#include "ui/gtk/gui_stat_menu.h"
|
|
|
|
#include "ui/gtk/stock_icons.h"
|
|
|
|
#include "ui/gtk/dlg_utils.h"
|
|
|
|
#include "ui/gtk/filter_dlg.h"
|
|
|
|
#include "ui/gtk/help_dlg.h"
|
|
|
|
#include "ui/gtk/pixmap_save.h"
|
|
|
|
#include "ui/gtk/main.h"
|
|
|
|
#include "ui/gtk/filter_autocomplete.h"
|
2012-04-01 16:01:12 +00:00
|
|
|
#include "ui/main_statusbar.h"
|
2008-04-13 03:32:24 +00:00
|
|
|
|
2012-01-15 21:59:11 +00:00
|
|
|
#include "ui/gtk/old-gtk-compat.h"
|
2013-01-04 17:07:26 +00:00
|
|
|
#include "ui/gtk/gui_utils.h"
|
2002-12-16 21:18:37 +00:00
|
|
|
|
2014-01-17 19:21:41 +00:00
|
|
|
void register_tap_listener_gtk_iostat(void);
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
#define MAX_GRAPHS 5
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
#define MAX_YSCALE 28
|
|
|
|
#define LOGARITHMIC_YSCALE 0
|
|
|
|
#define AUTO_MAX_YSCALE 1
|
2010-08-18 22:20:01 +00:00
|
|
|
#define DEFAULT_YSCALE_INDEX 1
|
2013-01-15 15:16:53 +00:00
|
|
|
static guint32 yscale_max[MAX_YSCALE] = {LOGARITHMIC_YSCALE, AUTO_MAX_YSCALE, 10, 20,
|
|
|
|
50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000,
|
|
|
|
50000, 100000, 200000, 500000, 1000000, 2000000,
|
|
|
|
5000000, 10000000, 20000000, 50000000, 100000000,
|
|
|
|
200000000, 500000000, 1000000000, 2000000000};
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
#define NO_FILTER_ORDER 0
|
2011-08-22 14:22:50 +00:00
|
|
|
#define MAX_MOVING_AVERAGE_ORDER 10
|
2013-01-15 15:16:53 +00:00
|
|
|
static guint32 moving_average_orders[MAX_MOVING_AVERAGE_ORDER] = {NO_FILTER_ORDER, 4, 8, 16,
|
|
|
|
32, 64, 128, 256, 512, 1024};
|
|
|
|
#define NO_FILTER 0
|
2011-08-22 14:22:50 +00:00
|
|
|
#define MOVING_AVERAGE_FILTER 1
|
2013-01-15 15:16:53 +00:00
|
|
|
#define GRAPH_NOFILTER 0
|
|
|
|
#define GRAPH_FOLLOWFILTER 1
|
2011-08-22 14:22:50 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
#define MAX_PIXELS_PER_TICK 4
|
2010-08-18 22:20:01 +00:00
|
|
|
#define DEFAULT_PIXELS_PER_TICK_INDEX 2
|
2002-11-14 10:32:22 +00:00
|
|
|
static guint32 pixels_per_tick[MAX_PIXELS_PER_TICK] = {1, 2, 5, 10};
|
|
|
|
|
2003-10-14 09:03:03 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
#define DEFAULT_PLOT_STYLE 0
|
|
|
|
#define PLOT_STYLE_LINE 0
|
|
|
|
#define PLOT_STYLE_IMPULSE 1
|
|
|
|
#define PLOT_STYLE_FILLED_BAR 2
|
|
|
|
#define PLOT_STYLE_DOT 3
|
|
|
|
#define MAX_PLOT_STYLES 4
|
2005-08-06 14:03:14 +00:00
|
|
|
static const char *plot_style_name[MAX_PLOT_STYLES] = {
|
2013-01-15 15:16:53 +00:00
|
|
|
"Line",
|
|
|
|
"Impulse",
|
|
|
|
"FBar",
|
|
|
|
"Dot",
|
2003-10-14 09:03:03 +00:00
|
|
|
};
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
/*
|
|
|
|
* XXX - "Count types" and "calc types" are combined in io_graph_item_unit_t
|
|
|
|
* in io_graph_item_t. The Qt port treats these as a single Y Axis "value unit"
|
|
|
|
* type. Should we do the same here?
|
|
|
|
*/
|
2010-08-18 22:20:01 +00:00
|
|
|
#define DEFAULT_COUNT_TYPE 0
|
2003-10-11 11:23:52 +00:00
|
|
|
#define COUNT_TYPE_FRAMES 0
|
|
|
|
#define COUNT_TYPE_BYTES 1
|
2007-03-07 23:39:45 +00:00
|
|
|
#define COUNT_TYPE_BITS 2
|
|
|
|
#define COUNT_TYPE_ADVANCED 3
|
2007-12-29 20:57:15 +00:00
|
|
|
#define MAX_COUNT_TYPES 4
|
2013-01-15 15:16:53 +00:00
|
|
|
static const char *count_type_names[MAX_COUNT_TYPES] = {
|
|
|
|
"Packets/Tick",
|
|
|
|
"Bytes/Tick",
|
|
|
|
"Bits/Tick",
|
|
|
|
"Advanced..."};
|
2002-11-16 11:45:58 +00:00
|
|
|
|
|
|
|
/* unit is in ms */
|
2007-09-26 22:50:53 +00:00
|
|
|
#define MAX_TICK_VALUES 7
|
2010-08-18 22:20:01 +00:00
|
|
|
#define DEFAULT_TICK_VALUE_INDEX 3
|
2007-09-26 22:50:53 +00:00
|
|
|
static const guint tick_interval_values[MAX_TICK_VALUES] = { 1, 10, 100, 1000, 10000, 60000, 600000 };
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
#define CALC_TYPE_SUM 0
|
|
|
|
#define CALC_TYPE_COUNT_FRAMES 1
|
|
|
|
#define CALC_TYPE_COUNT_FIELDS 2
|
|
|
|
#define CALC_TYPE_MAX 3
|
|
|
|
#define CALC_TYPE_MIN 4
|
|
|
|
#define CALC_TYPE_AVG 5
|
|
|
|
#define CALC_TYPE_LOAD 6
|
|
|
|
#define MAX_CALC_TYPES 7
|
|
|
|
#define DEFAULT_CALC_TYPE 0
|
|
|
|
static const char *calc_type_names[MAX_CALC_TYPES] = {
|
|
|
|
"SUM(*)",
|
|
|
|
"COUNT FRAMES(*)",
|
|
|
|
"COUNT FIELDS(*)",
|
|
|
|
"MAX(*)",
|
|
|
|
"MIN(*)",
|
|
|
|
"AVG(*)",
|
|
|
|
"LOAD(*)"};
|
2002-11-14 10:32:22 +00:00
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
#define CALC_TYPE_TO_ITEM_UNIT(ct) ((io_graph_item_unit_t)(ct + IOG_ITEM_UNIT_CALC_SUM))
|
2002-11-14 10:32:22 +00:00
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
/* Unused? */
|
|
|
|
#if 0
|
2003-10-12 04:20:03 +00:00
|
|
|
typedef struct _io_stat_calc_type_t {
|
2013-01-15 15:16:53 +00:00
|
|
|
struct _io_stat_graph_t *gio;
|
|
|
|
int calc_type;
|
2003-10-12 04:20:03 +00:00
|
|
|
} io_stat_calc_type_t;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
#endif
|
2003-10-12 04:20:03 +00:00
|
|
|
|
|
|
|
#define NUM_IO_ITEMS 100000
|
2002-11-14 10:32:22 +00:00
|
|
|
typedef struct _io_stat_graph_t {
|
2013-01-15 15:16:53 +00:00
|
|
|
struct _io_stat_t *io;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
io_graph_item_t items[NUM_IO_ITEMS];
|
2013-01-15 15:16:53 +00:00
|
|
|
int plot_style;
|
|
|
|
gboolean display;
|
|
|
|
GtkWidget *display_button;
|
|
|
|
GtkWidget *filter_field;
|
|
|
|
GtkWidget *advanced_buttons;
|
|
|
|
int calc_type;
|
|
|
|
int hf_index;
|
|
|
|
GtkWidget *calc_field;
|
|
|
|
GdkColor color;
|
|
|
|
GdkRGBA rgba_color;
|
|
|
|
construct_args_t *args;
|
|
|
|
GtkWidget *filter_bt;
|
|
|
|
|
|
|
|
gboolean follow_smooth;
|
|
|
|
GtkWidget *follow_smooth_toggle;
|
2002-11-14 10:32:22 +00:00
|
|
|
} io_stat_graph_t;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _io_stat_t {
|
2013-01-15 15:16:53 +00:00
|
|
|
gboolean needs_redraw;
|
|
|
|
guint32 interval; /* measurement interval in ms */
|
|
|
|
guint32 last_interval; /* the last *displayed* interval */
|
|
|
|
guint32 max_interval; /* the maximum interval based on the capture duration */
|
|
|
|
guint32 num_items; /* total number of items in all intervals (zero relative) */
|
|
|
|
guint32 left_x_border;
|
|
|
|
guint32 right_x_border;
|
|
|
|
gboolean view_as_time;
|
|
|
|
nstime_t start_time;
|
|
|
|
|
|
|
|
struct _io_stat_graph_t graphs[MAX_GRAPHS];
|
|
|
|
GtkWidget *window;
|
|
|
|
GtkWidget *draw_area;
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_surface_t *surface;
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
GdkPixmap *pixmap;
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkAdjustment *scrollbar_adjustment;
|
|
|
|
GtkWidget *scrollbar;
|
2012-04-01 16:01:12 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
int surface_width;
|
|
|
|
int surface_height;
|
|
|
|
int pixels_per_tick;
|
|
|
|
int max_y_units;
|
|
|
|
int count_type;
|
2011-08-22 14:22:50 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
guint32 filter_order;
|
|
|
|
int filter_type;
|
2008-08-05 17:33:14 +00:00
|
|
|
} io_stat_t;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
|
|
|
|
2002-11-29 11:37:33 +00:00
|
|
|
static void init_io_stat_window(io_stat_t *io);
|
2010-08-18 22:20:01 +00:00
|
|
|
static void filter_callback(GtkWidget *widget _U_, gpointer user_data);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2003-09-26 02:09:44 +00:00
|
|
|
static void
|
|
|
|
io_stat_set_title(io_stat_t *io)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
if (!io->window) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_window_title(io->window, "Wireshark IO Graphs");
|
2003-09-26 02:09:44 +00:00
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
|
|
|
|
static void
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
io_stat_reset(io_stat_t *io)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
int i;
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
io->needs_redraw = TRUE;
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
reset_io_graph_items((io_graph_item_t *)io->graphs[i].items, NUM_IO_ITEMS);
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
io->last_interval = 0xffffffff;
|
|
|
|
io->max_interval = 0;
|
|
|
|
io->num_items = 0;
|
|
|
|
io->start_time.secs = 0;
|
|
|
|
io->start_time.nsecs = 0;
|
|
|
|
io_stat_set_title(io);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
tap_iostat_reset(void *g)
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *gio = (io_stat_graph_t *)g;
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_reset(gio->io);
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static gboolean
|
|
|
|
tap_iostat_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *graph = (io_stat_graph_t *)g;
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_t *io;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
epan_dissect_t *adv_edt = NULL;
|
2013-01-15 15:16:53 +00:00
|
|
|
int idx;
|
|
|
|
|
|
|
|
/* we sometimes get called when the graph is disabled.
|
|
|
|
this is a bug since the tap listener should be removed first */
|
|
|
|
if (!graph->display) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
io = graph->io; /* Point up to the parent io_stat_t struct */
|
|
|
|
io->needs_redraw = TRUE;
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
idx = get_io_graph_index(pinfo, io->interval);
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
/* some sanity checks */
|
|
|
|
if ((idx < 0) || (idx >= NUM_IO_ITEMS)) {
|
|
|
|
io->num_items = NUM_IO_ITEMS-1;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update num_items */
|
|
|
|
if ((guint32)idx > io->num_items) {
|
|
|
|
io->num_items = (guint32) idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set start time */
|
|
|
|
if ((io->start_time.secs == 0) && (io->start_time.nsecs == 0)) {
|
2013-07-21 23:07:33 +00:00
|
|
|
nstime_delta(&io->start_time, &pinfo->fd->abs_ts, &pinfo->rel_ts);
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
/* For ADVANCED mode we need to keep track of some more stuff than just frame and byte counts */
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->count_type == COUNT_TYPE_ADVANCED) {
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
adv_edt = edt;
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
if (!update_io_graph_item((io_graph_item_t*) graph->items, idx, pinfo, adv_edt, graph->hf_index, CALC_TYPE_TO_ITEM_UNIT(graph->calc_type), io->interval)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
return TRUE;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-06 18:54:18 +00:00
|
|
|
static guint64
|
2012-04-01 16:01:12 +00:00
|
|
|
get_it_value(io_stat_t *io, int graph, int idx)
|
2002-11-29 11:37:33 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
guint64 value = 0; /* FIXME: loss of precision, visible on the graph for small values */
|
|
|
|
int adv_type;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
io_graph_item_t *it;
|
2013-01-15 15:16:53 +00:00
|
|
|
guint32 interval;
|
|
|
|
|
2013-04-16 16:16:15 +00:00
|
|
|
g_assert(graph < MAX_GRAPHS);
|
|
|
|
g_assert(idx < NUM_IO_ITEMS);
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
it = &io->graphs[graph].items[idx];
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
switch (io->count_type) {
|
|
|
|
case COUNT_TYPE_FRAMES:
|
|
|
|
return it->frames;
|
|
|
|
case COUNT_TYPE_BYTES:
|
|
|
|
return it->bytes;
|
|
|
|
case COUNT_TYPE_BITS:
|
|
|
|
return (it->bytes * 8);
|
|
|
|
case COUNT_TYPE_ADVANCED:
|
|
|
|
switch (io->graphs[graph].calc_type) {
|
|
|
|
case CALC_TYPE_COUNT_FRAMES:
|
|
|
|
return it->frames;
|
|
|
|
case CALC_TYPE_COUNT_FIELDS:
|
|
|
|
return it->fields;
|
|
|
|
default:
|
|
|
|
/* If it's COUNT_TYPE_ADVANCED but not one of the
|
|
|
|
* generic ones we'll get it when we switch on the
|
|
|
|
* adv_type below. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
adv_type = proto_registrar_get_ftype(io->graphs[graph].hf_index);
|
|
|
|
switch (adv_type) {
|
|
|
|
case FT_UINT8:
|
|
|
|
case FT_UINT16:
|
|
|
|
case FT_UINT24:
|
|
|
|
case FT_UINT32:
|
|
|
|
case FT_UINT64:
|
|
|
|
case FT_INT8:
|
|
|
|
case FT_INT16:
|
|
|
|
case FT_INT24:
|
|
|
|
case FT_INT32:
|
|
|
|
case FT_INT64:
|
|
|
|
switch (io->graphs[graph].calc_type) {
|
|
|
|
case CALC_TYPE_SUM:
|
|
|
|
value = it->int_tot;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MAX:
|
|
|
|
value = it->int_max;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MIN:
|
|
|
|
value = it->int_min;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_AVG:
|
|
|
|
if (it->fields) {
|
|
|
|
value = it->int_tot/it->fields;
|
|
|
|
} else {
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FT_FLOAT:
|
|
|
|
switch (io->graphs[graph].calc_type) {
|
|
|
|
case CALC_TYPE_SUM:
|
|
|
|
value = (guint64)it->float_tot;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MAX:
|
|
|
|
value = (guint64)it->float_max;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MIN:
|
|
|
|
value = (guint64)it->float_min;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_AVG:
|
|
|
|
if (it->fields) {
|
|
|
|
value = (guint64)it->float_tot/it->fields;
|
|
|
|
} else {
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FT_DOUBLE:
|
|
|
|
switch (io->graphs[graph].calc_type) {
|
|
|
|
case CALC_TYPE_SUM:
|
|
|
|
value = (guint64)it->double_tot;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MAX:
|
|
|
|
value = (guint64)it->double_max;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MIN:
|
|
|
|
value = (guint64)it->double_min;
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_AVG:
|
|
|
|
if (it->fields) {
|
|
|
|
value = (guint64)it->double_tot/it->fields;
|
|
|
|
} else {
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FT_RELATIVE_TIME:
|
|
|
|
switch (io->graphs[graph].calc_type) {
|
|
|
|
case CALC_TYPE_MAX:
|
|
|
|
value = (guint64) (it->time_max.secs*1000000 + it->time_max.nsecs/1000);
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_MIN:
|
|
|
|
value = (guint64) (it->time_min.secs*1000000 + it->time_min.nsecs/1000);
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_SUM:
|
|
|
|
value = (guint64) (it->time_tot.secs*1000000 + it->time_tot.nsecs/1000);
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_AVG:
|
|
|
|
if (it->fields) {
|
|
|
|
guint64 t; /* time in us */
|
|
|
|
|
|
|
|
t = it->time_tot.secs;
|
|
|
|
t = t*1000000+it->time_tot.nsecs/1000;
|
|
|
|
value = (guint64) (t/it->fields);
|
|
|
|
} else {
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CALC_TYPE_LOAD:
|
|
|
|
if (idx == (int)io->num_items) {
|
|
|
|
interval = (guint32)((cfile.elapsed_time.secs*1000) +
|
|
|
|
((cfile.elapsed_time.nsecs+500000)/1000000));
|
|
|
|
interval -= (io->interval * idx);
|
|
|
|
} else {
|
|
|
|
interval = io->interval;
|
|
|
|
}
|
|
|
|
value = (guint64) ((it->time_tot.secs*1000000 + it->time_tot.nsecs/1000) / interval);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return value;
|
2002-11-29 11:37:33 +00:00
|
|
|
}
|
|
|
|
|
2003-10-11 23:17:46 +00:00
|
|
|
static void
|
2010-01-29 23:17:32 +00:00
|
|
|
print_time_scale_string(char *buf, int buf_len, guint32 t, guint32 t_max, gboolean log_flag)
|
2003-10-11 23:17:46 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
if ((t_max >= 10000000) || (log_flag && (t_max >= 1000000))) {
|
|
|
|
g_snprintf(buf, buf_len, "%ds", t/1000000);
|
|
|
|
} else if (t_max >= 1000000) {
|
|
|
|
g_snprintf(buf, buf_len, "%d.%1ds", t/1000000, (t%1000000)/100000);
|
|
|
|
} else if ((t_max >= 10000) || (log_flag && (t_max >= 1000))) {
|
|
|
|
g_snprintf(buf, buf_len, "%dms", t/1000);
|
|
|
|
} else if (t_max >= 1000) {
|
|
|
|
g_snprintf(buf, buf_len, "%d.%1dms", t/1000,(t%1000)/100);
|
|
|
|
} else {
|
|
|
|
g_snprintf(buf, buf_len, "%dus", t);
|
|
|
|
}
|
2003-10-11 23:17:46 +00:00
|
|
|
}
|
|
|
|
|
2008-01-20 12:24:14 +00:00
|
|
|
static void
|
|
|
|
print_interval_string(char *buf, int buf_len, guint32 interval, io_stat_t *io,
|
2013-01-15 15:16:53 +00:00
|
|
|
gboolean ext)
|
2008-01-20 12:24:14 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->view_as_time) {
|
|
|
|
struct tm *tmp;
|
|
|
|
time_t sec_val = interval/1000 + io->start_time.secs;
|
|
|
|
gint32 nsec_val = interval%1000 + io->start_time.nsecs/1000000;
|
|
|
|
|
|
|
|
if (nsec_val >= 1000) {
|
|
|
|
sec_val++;
|
|
|
|
nsec_val -= 1000;
|
|
|
|
}
|
|
|
|
tmp = localtime (&sec_val);
|
|
|
|
if (io->interval >= 1000) {
|
|
|
|
g_snprintf(buf, buf_len, "%02d:%02d:%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
|
|
} else if (io->interval >= 100) {
|
|
|
|
g_snprintf(buf, buf_len, "%02d:%02d:%02d.%1d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val/100);
|
|
|
|
} else if (io->interval >= 10) {
|
|
|
|
g_snprintf(buf, buf_len, "%02d:%02d:%02d.%02d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val/10);
|
|
|
|
} else {
|
|
|
|
g_snprintf(buf, buf_len, "%02d:%02d:%02d.%03d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, nsec_val);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!ext) {
|
|
|
|
g_snprintf(buf, buf_len, "%d.%03d", interval/1000,interval%1000);
|
|
|
|
} else if (io->interval >= 60000) {
|
|
|
|
g_snprintf(buf, buf_len, "%dm", interval/60000);
|
|
|
|
} else if (io->interval >= 1000) {
|
|
|
|
g_snprintf(buf, buf_len, "%ds", interval/1000);
|
|
|
|
} else if (io->interval >= 100) {
|
|
|
|
g_snprintf(buf, buf_len, "%d.%1ds", interval/1000,(interval/100)%10);
|
|
|
|
} else if (io->interval >= 10) {
|
|
|
|
g_snprintf(buf, buf_len, "%d.%02ds", interval/1000,(interval/10)%100);
|
|
|
|
} else {
|
|
|
|
g_snprintf(buf, buf_len, "%d.%03ds", interval/1000,interval%1000);
|
|
|
|
}
|
|
|
|
}
|
2008-01-20 12:24:14 +00:00
|
|
|
}
|
|
|
|
|
2002-11-14 10:32:22 +00:00
|
|
|
static void
|
2013-07-09 16:58:07 +00:00
|
|
|
io_stat_draw(io_stat_t *io)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
int i, tics, ystart, ys;
|
|
|
|
guint32 last_interval, first_interval, interval_delta;
|
|
|
|
gint32 current_interval;
|
|
|
|
guint32 top_y_border;
|
|
|
|
guint32 bottom_y_border;
|
|
|
|
PangoLayout *layout;
|
|
|
|
int label_width, label_height;
|
|
|
|
guint32 draw_width, draw_height;
|
|
|
|
char label_string[45];
|
|
|
|
GtkAllocation widget_alloc;
|
|
|
|
|
2012-11-08 12:37:42 +00:00
|
|
|
/* new variables */
|
2013-01-15 15:16:53 +00:00
|
|
|
guint32 num_time_intervals; /* number of intervals relative to 1 */
|
|
|
|
guint64 max_value; /* max value of seen data */
|
|
|
|
guint32 max_y; /* max value of the Y scale */
|
|
|
|
gboolean draw_y_as_time;
|
2013-05-31 02:14:19 +00:00
|
|
|
gboolean draw_y_as_load;
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_t *cr;
|
2012-11-08 12:37:42 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (!io->needs_redraw) {
|
2012-11-08 12:37:42 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
io->needs_redraw = FALSE;
|
2012-11-08 12:37:42 +00:00
|
|
|
/*
|
|
|
|
* Set max_interval to duration rounded to the nearest ms. Add the Tick Interval so the last
|
2013-01-15 15:16:53 +00:00
|
|
|
* interval will be displayed. For example, if duration = 11.844 secs and 'Tick Interval' == 1,
|
|
|
|
* max_interval = 12000; if 0.1, 11900; if 0.01, 11850; and if 0.001, 11845.
|
2012-11-08 12:37:42 +00:00
|
|
|
*/
|
|
|
|
io->max_interval = (guint32)((cfile.elapsed_time.secs*1000) +
|
|
|
|
((cfile.elapsed_time.nsecs+500000)/1000000) +
|
|
|
|
io->interval);
|
|
|
|
io->max_interval = (io->max_interval / io->interval) * io->interval;
|
2013-04-16 16:16:15 +00:00
|
|
|
if (io->max_interval >= NUM_IO_ITEMS * io->interval) {
|
|
|
|
/* XXX: Truncate the graph if it covers too much real time, as
|
|
|
|
* otherwise we crash later trying to make the graph too wide. There's
|
|
|
|
* no good way of warning the user, since this gets recalculated a
|
|
|
|
* lot and any dialogue we pop up would spawn 100+ times when scrolling.
|
|
|
|
*
|
|
|
|
* Should at least stop us from crashing in:
|
|
|
|
* https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8583
|
|
|
|
*/
|
|
|
|
io->max_interval = (NUM_IO_ITEMS - 1) * io->interval;
|
|
|
|
}
|
2012-11-08 12:37:42 +00:00
|
|
|
/*
|
|
|
|
* Find the length of the intervals we have data for
|
|
|
|
* so we know how large arrays we need to malloc()
|
|
|
|
*/
|
|
|
|
num_time_intervals = io->num_items+1;
|
|
|
|
|
|
|
|
/* XXX move this check to _packet() */
|
2013-01-15 15:16:53 +00:00
|
|
|
if (num_time_intervals > NUM_IO_ITEMS) {
|
2012-11-08 12:37:42 +00:00
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "IO-Stat error. There are too many entries, bailing out");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find the max value so we can autoscale the y axis
|
|
|
|
*/
|
2013-01-15 15:16:53 +00:00
|
|
|
max_value = 0;
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
2012-11-08 12:37:42 +00:00
|
|
|
int idx;
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (!io->graphs[i].display) {
|
2012-11-08 12:37:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
for (idx=0; (guint32)(idx) < num_time_intervals; idx++) {
|
2012-11-08 12:37:42 +00:00
|
|
|
guint64 val;
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
val = get_it_value(io, i, idx);
|
2012-11-08 12:37:42 +00:00
|
|
|
|
|
|
|
/* keep track of the max value we have encountered */
|
2013-01-15 15:16:53 +00:00
|
|
|
if (val>max_value) {
|
|
|
|
max_value = val;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear out old plot
|
|
|
|
*/
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2012-11-08 12:37:42 +00:00
|
|
|
cr = cairo_create (io->surface);
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2012-11-08 12:37:42 +00:00
|
|
|
cr = gdk_cairo_create (io->pixmap);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_set_source_rgb (cr, 1, 1, 1);
|
|
|
|
gtk_widget_get_allocation(io->draw_area, &widget_alloc);
|
|
|
|
cairo_rectangle (cr, 0, 0, widget_alloc.width,widget_alloc.height);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
/*
|
|
|
|
* Calculate the y scale we should use
|
|
|
|
*/
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->max_y_units == AUTO_MAX_YSCALE) {
|
2012-11-08 12:37:42 +00:00
|
|
|
max_y = yscale_max[MAX_YSCALE-1];
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=MAX_YSCALE-1; i>1; i--) {
|
|
|
|
if (max_value < yscale_max[i]) {
|
2012-11-08 12:37:42 +00:00
|
|
|
max_y = yscale_max[i];
|
|
|
|
}
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
} else if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
2012-11-08 12:37:42 +00:00
|
|
|
max_y = 1000000000;
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=1000000000; i>1; i/=10) {
|
|
|
|
if (max_value<(guint32)i) {
|
|
|
|
max_y = i;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* the user had specified an explicit y scale to use */
|
2013-01-15 15:16:53 +00:00
|
|
|
max_y = io->max_y_units;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we use ADVANCED and all the graphs are plotting
|
|
|
|
* either MIN/MAX/AVG of an FT_RELATIVE_TIME field
|
|
|
|
* then we will do some some special processing for the
|
|
|
|
* labels for the Y axis below:
|
|
|
|
* we will append the time unit " s" " ms" or " us"
|
|
|
|
* and we will present the unit in decimal
|
|
|
|
*/
|
|
|
|
draw_y_as_time = FALSE;
|
2013-05-31 02:14:19 +00:00
|
|
|
draw_y_as_load = FALSE;
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->count_type == COUNT_TYPE_ADVANCED) {
|
2012-11-08 12:37:42 +00:00
|
|
|
draw_y_as_time = TRUE;
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
2012-11-08 12:37:42 +00:00
|
|
|
int adv_type;
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (!io->graphs[i].display) {
|
2012-11-08 12:37:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-05-31 02:14:19 +00:00
|
|
|
if (io->graphs[i].calc_type == CALC_TYPE_LOAD) {
|
|
|
|
draw_y_as_load = TRUE;
|
2013-07-09 16:58:07 +00:00
|
|
|
}
|
2013-05-31 02:14:19 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
adv_type = proto_registrar_get_ftype(io->graphs[i].hf_index);
|
|
|
|
switch (adv_type) {
|
2012-11-08 12:37:42 +00:00
|
|
|
case FT_RELATIVE_TIME:
|
2013-01-15 15:16:53 +00:00
|
|
|
switch (io->graphs[i].calc_type) {
|
2012-11-08 12:37:42 +00:00
|
|
|
case CALC_TYPE_SUM:
|
|
|
|
case CALC_TYPE_MAX:
|
|
|
|
case CALC_TYPE_MIN:
|
|
|
|
case CALC_TYPE_AVG:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
draw_y_as_time = FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
draw_y_as_time = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate size of borders surrounding the plot
|
|
|
|
* The border on the right side needs to be adjusted depending
|
|
|
|
* on the width of the text labels. For simplicity we assume that the
|
|
|
|
* top y scale label will be the widest one
|
|
|
|
*/
|
2013-01-15 15:16:53 +00:00
|
|
|
if (draw_y_as_time) {
|
|
|
|
if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
2013-07-09 16:58:07 +00:00
|
|
|
print_time_scale_string(label_string, sizeof(label_string), 100000, 100000, TRUE); /* 100 ms */
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-07-09 16:58:07 +00:00
|
|
|
print_time_scale_string(label_string, sizeof(label_string), max_y, max_y, FALSE);
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
} else {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d", max_y);
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
layout = gtk_widget_create_pango_layout(io->draw_area, label_string);
|
|
|
|
pango_layout_get_pixel_size(layout, &label_width, &label_height);
|
|
|
|
|
|
|
|
io->left_x_border = 10;
|
|
|
|
io->right_x_border = label_width + 20;
|
|
|
|
top_y_border = 10;
|
|
|
|
bottom_y_border = label_height + 20;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the size of the drawing area for the actual plot
|
|
|
|
*/
|
|
|
|
draw_width = io->surface_width-io->right_x_border - io->left_x_border;
|
|
|
|
draw_height = io->surface_height-top_y_border - bottom_y_border;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add a warning if too many entries
|
|
|
|
*/
|
|
|
|
if (num_time_intervals >= NUM_IO_ITEMS-1) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf (label_string, sizeof(label_string), "Warning: Graph limited to %d entries", NUM_IO_ITEMS);
|
2012-11-08 12:37:42 +00:00
|
|
|
pango_layout_set_text(layout, label_string, -1);
|
2011-07-23 11:27:57 +00:00
|
|
|
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2012-11-08 12:37:42 +00:00
|
|
|
cr = cairo_create (io->surface);
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2012-11-08 12:37:42 +00:00
|
|
|
cr = gdk_cairo_create (io->pixmap);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_move_to (cr, 5, io->surface_height-bottom_y_border-draw_height-label_height/2);
|
|
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
cr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw the y axis and labels
|
|
|
|
* (we always draw the y scale with 11 ticks along the axis)
|
|
|
|
*/
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2012-11-08 12:37:42 +00:00
|
|
|
cr = cairo_create (io->surface);
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2012-11-08 12:37:42 +00:00
|
|
|
cr = gdk_cairo_create (io->pixmap);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_set_line_width (cr, 1.0);
|
|
|
|
cairo_move_to(cr, io->surface_width-io->right_x_border+1.5, top_y_border + 0.5);
|
|
|
|
cairo_line_to(cr, io->surface_width-io->right_x_border+1.5, io->surface_height-bottom_y_border + 0.5);
|
|
|
|
cairo_stroke(cr);
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
2012-11-08 12:37:42 +00:00
|
|
|
tics = (int)log10((double)max_y);
|
|
|
|
ystart = draw_height/10;
|
|
|
|
ys = -1;
|
|
|
|
} else {
|
|
|
|
tics = 10;
|
2013-01-15 15:16:53 +00:00
|
|
|
ystart = ys = 0;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=ys; i<=tics; i++) {
|
2012-11-08 12:37:42 +00:00
|
|
|
int xwidth, lwidth, ypos;
|
|
|
|
|
|
|
|
xwidth = 5;
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
|
|
|
if (i == ys) {
|
2012-11-08 12:37:42 +00:00
|
|
|
/* position for the 0 value */
|
2013-01-15 15:16:53 +00:00
|
|
|
ypos = io->surface_height-bottom_y_border;
|
|
|
|
} else if (i == tics) {
|
2012-11-08 12:37:42 +00:00
|
|
|
/* position for the top value, do not draw logarithmic tics above graph */
|
2013-01-15 15:16:53 +00:00
|
|
|
ypos = io->surface_height-bottom_y_border-draw_height;
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
|
|
|
int j;
|
|
|
|
/* draw the logarithmic tics */
|
2013-01-15 15:16:53 +00:00
|
|
|
for (j=2; j<10; j++) {
|
|
|
|
ypos = (int)(io->surface_height
|
|
|
|
- bottom_y_border
|
|
|
|
- (draw_height - ystart) * (i + log10((double)j))/tics
|
|
|
|
- ystart);
|
2012-11-08 12:37:42 +00:00
|
|
|
/* draw the tick */
|
|
|
|
cairo_move_to(cr, io->surface_width-io->right_x_border+1.5, ypos+0.5);
|
|
|
|
cairo_line_to(cr, io->surface_width-io->right_x_border+1.5+xwidth,ypos+0.5);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
ypos = io->surface_height-bottom_y_border-(draw_height-ystart)*i/tics-ystart;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
/* all "main" logarithmic lines are slightly longer */
|
2013-01-15 15:16:53 +00:00
|
|
|
xwidth = 10;
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
|
|
|
if (!(i%5)) {
|
|
|
|
/* first, middle and last tick are slightly longer */
|
|
|
|
xwidth = 10;
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
ypos = io->surface_height-bottom_y_border-draw_height*i/10;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
/* draw the tick */
|
|
|
|
cairo_move_to(cr, io->surface_width-io->right_x_border+1.5, ypos+0.5);
|
|
|
|
cairo_line_to(cr, io->surface_width-io->right_x_border+1.5+xwidth,ypos+0.5);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
/* draw the labels */
|
2013-01-15 15:16:53 +00:00
|
|
|
if (xwidth == 10) {
|
2012-11-08 12:37:42 +00:00
|
|
|
guint32 value;
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
2012-11-08 12:37:42 +00:00
|
|
|
value = (guint32)(max_y / pow(10,tics-i));
|
2013-01-15 15:16:53 +00:00
|
|
|
if (draw_y_as_time) {
|
2013-07-09 16:58:07 +00:00
|
|
|
print_time_scale_string(label_string, sizeof(label_string), value, value, TRUE);
|
2013-05-31 02:14:19 +00:00
|
|
|
} else if (draw_y_as_load) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d.%1d", value/1000, (value/100)%10);
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d", value);
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
value = (max_y/10)*i;
|
2013-01-15 15:16:53 +00:00
|
|
|
if (draw_y_as_time) {
|
2013-07-09 16:58:07 +00:00
|
|
|
print_time_scale_string(label_string, sizeof(label_string), value, max_y, FALSE);
|
2013-05-31 02:14:19 +00:00
|
|
|
} else if (draw_y_as_load) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d.%1d", value/1000, (value/100)%10);
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(label_string, sizeof(label_string), "%d", value);
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
2011-07-23 11:27:57 +00:00
|
|
|
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_move_to (cr, io->surface_width-io->right_x_border+15+label_width-lwidth, ypos-label_height/2);
|
|
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have not specified the last_interval via the GUI, just pick the current end of the
|
|
|
|
* capture so that it scrolls nicely when doing live captures.
|
|
|
|
*/
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->last_interval == 0xffffffff) {
|
2012-11-08 12:37:42 +00:00
|
|
|
last_interval = io->max_interval;
|
|
|
|
} else {
|
|
|
|
last_interval = io->last_interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*XXX*/
|
|
|
|
/* plot the x-scale */
|
|
|
|
cairo_move_to(cr, io->left_x_border+0.5, io->surface_height-bottom_y_border+1.5);
|
|
|
|
cairo_line_to(cr, io->surface_width-io->right_x_border+1.5,io->surface_height-bottom_y_border+1.5);
|
|
|
|
cairo_stroke(cr);
|
2013-01-15 15:16:53 +00:00
|
|
|
if ((last_interval/io->interval) >= draw_width/io->pixels_per_tick) {
|
|
|
|
first_interval = (last_interval/io->interval)-draw_width/io->pixels_per_tick+1;
|
|
|
|
first_interval *= io->interval;
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-01-15 15:16:53 +00:00
|
|
|
first_interval = 0;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
interval_delta = (100/io->pixels_per_tick)*io->interval;
|
|
|
|
for (current_interval = last_interval;
|
|
|
|
current_interval >= (gint32)first_interval;
|
|
|
|
current_interval = current_interval-io->interval) {
|
2012-11-08 12:37:42 +00:00
|
|
|
int x, xlen;
|
|
|
|
|
|
|
|
/* if pixels_per_tick is 1 or 2, only draw every 10 ticks */
|
|
|
|
/* if pixels_per_tick is 5, only draw every 5 ticks */
|
2013-01-15 15:16:53 +00:00
|
|
|
if (((io->pixels_per_tick < 5) && (current_interval % (10*io->interval))) ||
|
|
|
|
((io->pixels_per_tick == 5) && (current_interval % (5*io->interval)))) {
|
2012-11-08 12:37:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (!(current_interval%interval_delta)) {
|
|
|
|
xlen = 10;
|
|
|
|
} else if (!(current_interval%(interval_delta/2))) {
|
|
|
|
xlen = 8;
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-01-15 15:16:53 +00:00
|
|
|
xlen = 5;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
x = draw_width+io->left_x_border-((last_interval-current_interval)/io->interval)*io->pixels_per_tick;
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_move_to(cr, x-1-io->pixels_per_tick/2+0.5, io->surface_height-bottom_y_border+1.5);
|
|
|
|
cairo_line_to(cr, x-1-io->pixels_per_tick/2+0.5, io->surface_height-bottom_y_border+xlen+1.5);
|
|
|
|
cairo_stroke(cr);
|
2013-01-15 15:16:53 +00:00
|
|
|
if (xlen == 10) {
|
2012-11-08 12:37:42 +00:00
|
|
|
int lwidth, x_pos;
|
2013-07-09 16:58:07 +00:00
|
|
|
print_interval_string (label_string, sizeof(label_string), current_interval, io, TRUE);
|
2012-11-08 12:37:42 +00:00
|
|
|
pango_layout_set_text(layout, label_string, -1);
|
|
|
|
pango_layout_get_pixel_size(layout, &lwidth, NULL);
|
|
|
|
|
|
|
|
if ((x-1-io->pixels_per_tick/2-lwidth/2) < 5) {
|
2013-01-15 15:16:53 +00:00
|
|
|
x_pos = 5;
|
2012-11-08 12:37:42 +00:00
|
|
|
} else if ((x-1-io->pixels_per_tick/2+lwidth/2) > (io->surface_width-5)) {
|
2013-01-15 15:16:53 +00:00
|
|
|
x_pos = io->surface_width-lwidth-5;
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-01-15 15:16:53 +00:00
|
|
|
x_pos = x-1-io->pixels_per_tick/2-lwidth/2;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
cairo_move_to (cr, x_pos, io->surface_height-bottom_y_border+15);
|
|
|
|
pango_cairo_show_layout (cr, layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2012-11-08 13:18:23 +00:00
|
|
|
cairo_destroy (cr);
|
|
|
|
cr = NULL;
|
2012-11-08 12:37:42 +00:00
|
|
|
g_object_unref(G_OBJECT(layout));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop over all graphs and draw them
|
|
|
|
*/
|
2012-11-08 12:52:08 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
|
|
|
cr = cairo_create (io->surface);
|
|
|
|
#else
|
|
|
|
cr = gdk_cairo_create (io->pixmap);
|
|
|
|
#endif
|
|
|
|
cairo_set_line_width (cr, 1.0);
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=MAX_GRAPHS-1; i>=0; i--) {
|
2012-11-08 12:37:42 +00:00
|
|
|
guint64 val;
|
|
|
|
guint32 interval, x_pos, y_pos, prev_x_pos, prev_y_pos;
|
|
|
|
/* Moving average variables */
|
|
|
|
guint32 mavg_in_average_count = 0, mavg_left = 0, mavg_right = 0;
|
|
|
|
guint64 mavg_cumulated = 0;
|
|
|
|
guint64 mavg_to_remove = 0, mavg_to_add = 0;
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (!io->graphs[i].display) {
|
2012-11-08 12:37:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if ((io->graphs[i].follow_smooth == GRAPH_FOLLOWFILTER) &&
|
|
|
|
(io->filter_type == MOVING_AVERAGE_FILTER)) {
|
2012-11-08 12:37:42 +00:00
|
|
|
/* "Warm-up phase" - calculate average on some data not displayed;
|
|
|
|
just to make sure average on leftmost and rightmost displayed
|
|
|
|
values is as reliable as possible
|
|
|
|
*/
|
|
|
|
guint64 warmup_interval;
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (first_interval/io->interval > io->filter_order/2) {
|
2012-11-08 12:37:42 +00:00
|
|
|
warmup_interval = first_interval/io->interval - io->filter_order/2;
|
|
|
|
warmup_interval *= io->interval;
|
|
|
|
} else {
|
|
|
|
warmup_interval = 0;
|
|
|
|
}
|
|
|
|
mavg_to_remove = warmup_interval;
|
2013-01-15 15:16:53 +00:00
|
|
|
for (; warmup_interval < first_interval; warmup_interval += io->interval) {
|
2012-11-08 12:37:42 +00:00
|
|
|
mavg_cumulated += get_it_value(io, i, (int)warmup_interval/io->interval);
|
|
|
|
mavg_in_average_count++;
|
|
|
|
mavg_left++;
|
|
|
|
}
|
|
|
|
mavg_cumulated += get_it_value(io, i, (int)warmup_interval/io->interval);
|
|
|
|
mavg_in_average_count++;
|
2013-01-15 15:16:53 +00:00
|
|
|
for (warmup_interval += io->interval;
|
2012-11-08 12:37:42 +00:00
|
|
|
((warmup_interval < (first_interval + (io->filter_order/2) * (guint64)io->interval)) &&
|
2013-01-15 15:16:53 +00:00
|
|
|
(warmup_interval <= (io->num_items * (guint64)io->interval)));
|
|
|
|
warmup_interval += io->interval) {
|
2012-11-08 12:37:42 +00:00
|
|
|
|
|
|
|
mavg_cumulated += get_it_value(io, i, (int)warmup_interval / io->interval);
|
|
|
|
mavg_in_average_count++;
|
|
|
|
mavg_right++;
|
|
|
|
}
|
|
|
|
mavg_to_add = warmup_interval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize prev x/y to the value of the first interval */
|
|
|
|
prev_x_pos = draw_width-1 -
|
|
|
|
io->pixels_per_tick * ((last_interval - first_interval) / io->interval) +
|
|
|
|
io->left_x_border;
|
|
|
|
val = get_it_value(io, i, first_interval / io->interval);
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if ((io->graphs[i].follow_smooth == GRAPH_FOLLOWFILTER) &&
|
|
|
|
(io->filter_type == MOVING_AVERAGE_FILTER) &&
|
|
|
|
(mavg_in_average_count > 0)) {
|
2012-11-08 12:37:42 +00:00
|
|
|
val = mavg_cumulated / mavg_in_average_count;
|
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (val>max_y) {
|
|
|
|
prev_y_pos = 0;
|
|
|
|
} else if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
|
|
|
if (val == 0) {
|
2012-11-08 12:37:42 +00:00
|
|
|
prev_y_pos = (guint32)(draw_height - 1 + top_y_border);
|
|
|
|
} else {
|
|
|
|
prev_y_pos = (guint32) (
|
|
|
|
(draw_height - ystart)-1 -
|
|
|
|
((log10((double)((gint64)val)) * (draw_height - ystart)) / log10((double)max_y)) +
|
|
|
|
top_y_border
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
2013-01-15 15:16:53 +00:00
|
|
|
prev_y_pos = (guint32)(draw_height-1-(val*draw_height)/max_y+top_y_border);
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
for (interval = first_interval;
|
|
|
|
interval < last_interval;
|
|
|
|
interval += io->interval) {
|
|
|
|
x_pos = draw_width-1-io->pixels_per_tick*((last_interval-interval)/io->interval)+io->left_x_border;
|
2012-11-08 12:37:42 +00:00
|
|
|
|
|
|
|
val = get_it_value(io, i, interval/io->interval);
|
|
|
|
/* Moving average calculation */
|
2013-01-15 15:16:53 +00:00
|
|
|
if ((io->graphs[i].follow_smooth == GRAPH_FOLLOWFILTER) &&
|
|
|
|
(io->filter_type == MOVING_AVERAGE_FILTER)) {
|
|
|
|
if (interval != first_interval) {
|
2012-11-08 12:37:42 +00:00
|
|
|
mavg_left++;
|
|
|
|
if (mavg_left > io->filter_order/2) {
|
|
|
|
mavg_left--;
|
|
|
|
mavg_in_average_count--;
|
|
|
|
mavg_cumulated -= get_it_value(io, i, (int)mavg_to_remove/io->interval);
|
|
|
|
mavg_to_remove += io->interval;
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
if (mavg_to_add<=(guint64)io->num_items*io->interval) {
|
2012-11-08 12:37:42 +00:00
|
|
|
mavg_in_average_count++;
|
|
|
|
mavg_cumulated += get_it_value(io, i, (int)mavg_to_add/io->interval);
|
|
|
|
mavg_to_add += io->interval;
|
|
|
|
} else {
|
|
|
|
mavg_right--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mavg_in_average_count > 0) {
|
|
|
|
val = mavg_cumulated / mavg_in_average_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val>max_y) {
|
2013-01-15 15:16:53 +00:00
|
|
|
y_pos = 0;
|
|
|
|
} else if (io->max_y_units == LOGARITHMIC_YSCALE) {
|
|
|
|
if (val == 0) {
|
|
|
|
y_pos = (guint32)(draw_height-1+top_y_border);
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
|
|
|
y_pos = (guint32) (
|
|
|
|
(draw_height - ystart) - 1 -
|
|
|
|
(log10((double)(gint64)val) * (draw_height - ystart)) / log10((double)max_y) +
|
|
|
|
top_y_border
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
y_pos = (guint32)(draw_height - 1 -
|
|
|
|
((val * draw_height) / max_y) +
|
|
|
|
top_y_border);
|
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
switch (io->graphs[i].plot_style) {
|
2012-11-08 12:37:42 +00:00
|
|
|
case PLOT_STYLE_LINE:
|
|
|
|
/* Dont draw anything if the segment entirely above the top of the graph
|
|
|
|
*/
|
2013-01-15 15:16:53 +00:00
|
|
|
if ( (prev_y_pos != 0) || (y_pos != 0) ) {
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_move_to(cr, prev_x_pos+0.5, prev_y_pos+0.5);
|
|
|
|
cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
|
2013-01-15 15:16:53 +00:00
|
|
|
gdk_cairo_set_source_rgba (cr, &io->graphs[i].rgba_color);
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PLOT_STYLE_IMPULSE:
|
2013-01-15 15:16:53 +00:00
|
|
|
if (val) {
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_move_to(cr, x_pos+0.5, draw_height-1+top_y_border+0.5);
|
|
|
|
cairo_line_to(cr, x_pos+0.5, y_pos+0.5);
|
2013-01-15 15:16:53 +00:00
|
|
|
gdk_cairo_set_source_rgba (cr, &io->graphs[i].rgba_color);
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PLOT_STYLE_FILLED_BAR:
|
2013-01-15 15:16:53 +00:00
|
|
|
if (val) {
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_rectangle (cr,
|
|
|
|
x_pos-(gdouble)io->pixels_per_tick/2+0.5,
|
|
|
|
y_pos+0.5,
|
|
|
|
io->pixels_per_tick,
|
|
|
|
draw_height-1+top_y_border-y_pos);
|
2013-01-15 15:16:53 +00:00
|
|
|
gdk_cairo_set_source_rgba (cr, &io->graphs[i].rgba_color);
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PLOT_STYLE_DOT:
|
2013-01-15 15:16:53 +00:00
|
|
|
if (val) {
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_arc (cr,
|
|
|
|
x_pos+0.5,
|
|
|
|
y_pos+0.5,
|
|
|
|
(gdouble)io->pixels_per_tick/2,
|
|
|
|
0,
|
|
|
|
2 * G_PI);
|
2013-01-15 15:16:53 +00:00
|
|
|
gdk_cairo_set_source_rgba (cr, &io->graphs[i].rgba_color);
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
prev_y_pos = y_pos;
|
|
|
|
prev_x_pos = x_pos;
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
}
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_destroy (cr);
|
2012-11-08 12:37:42 +00:00
|
|
|
|
|
|
|
cr = gdk_cairo_create (gtk_widget_get_window(io->draw_area));
|
2011-07-24 11:35:51 +00:00
|
|
|
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_set_source_surface (cr, io->surface, 0, 0);
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2012-11-08 12:37:42 +00:00
|
|
|
gdk_cairo_set_source_pixmap (cr, io->pixmap, 0, 0);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2012-11-08 12:37:42 +00:00
|
|
|
cairo_rectangle (cr, 0, 0, io->surface_width, io->surface_height);
|
|
|
|
cairo_fill (cr);
|
|
|
|
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
|
|
/* update the scrollbar */
|
|
|
|
if (io->max_interval == 0) {
|
2013-04-17 15:07:48 +00:00
|
|
|
gtk_adjustment_set_upper(io->scrollbar_adjustment, (gdouble) io->interval);
|
|
|
|
gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gdouble) (io->interval/10));
|
|
|
|
gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gdouble) io->interval);
|
2012-11-08 12:37:42 +00:00
|
|
|
} else {
|
2013-04-17 15:07:48 +00:00
|
|
|
gtk_adjustment_set_upper(io->scrollbar_adjustment, (gdouble) io->max_interval);
|
|
|
|
gtk_adjustment_set_step_increment(io->scrollbar_adjustment, (gdouble) ((last_interval-first_interval)/10));
|
|
|
|
gtk_adjustment_set_page_increment(io->scrollbar_adjustment, (gdouble) (last_interval-first_interval));
|
2012-11-08 12:37:42 +00:00
|
|
|
}
|
|
|
|
gtk_adjustment_set_page_size(io->scrollbar_adjustment, gtk_adjustment_get_page_increment(io->scrollbar_adjustment));
|
2013-04-17 15:07:48 +00:00
|
|
|
gtk_adjustment_set_value(io->scrollbar_adjustment, (gdouble)first_interval);
|
2012-11-08 12:37:42 +00:00
|
|
|
gtk_adjustment_changed(io->scrollbar_adjustment);
|
|
|
|
gtk_adjustment_value_changed(io->scrollbar_adjustment);
|
2003-10-11 11:23:52 +00:00
|
|
|
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
static void
|
|
|
|
io_stat_redraw(io_stat_t *io)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
io->needs_redraw = TRUE;
|
|
|
|
io_stat_draw(io);
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
tap_iostat_draw(void *g)
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *git = (io_stat_graph_t *)g;
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_draw(git->io);
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 17:33:14 +00:00
|
|
|
/* ok we get called with both the filter and the field.
|
2004-03-08 07:47:14 +00:00
|
|
|
make sure the field is part of the filter.
|
2013-07-09 16:58:07 +00:00
|
|
|
(make sure and just append it)
|
|
|
|
the field MUST be part of the filter or else we won't
|
2004-03-08 07:47:14 +00:00
|
|
|
be able to pick up the field values after the edt tree has been
|
2008-08-05 17:33:14 +00:00
|
|
|
pruned
|
2004-03-08 07:47:14 +00:00
|
|
|
*/
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
static GString *
|
"gtk_entry_get_text()" returns a "const char *" - assign the result to
one.
"get_basename()" doesn't modify its argument, and its callers don't
modify the substring pointed to by the result, so make it take a "const
char *" as an argument and return a "const char *".
"find_last_pathname_separator()" doesn't modify its argument, so make it
a "const char *" - but some of its callers pass a non-"const" "char *"
and modify the result, so don't make its return value a "const char *".
And, as none of its callers are outside "filesystem.c", make it static.
In "about_folders_page_new()", have separate variables for pathnames
returned as "const char *" (which are cached by the routine that returns
them, so you can't modify them - and can't free them, so get rid of the
commented-out "g_free()" calls for them) and pathnames returned as "char
*" (which are allocated anew for each call, and can be modified, but
have to be freed).
Clean up white space.
svn path=/trunk/; revision=12881
2004-12-31 00:26:36 +00:00
|
|
|
enable_graph(io_stat_graph_t *gio, const char *filter, const char *field)
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
{
|
2013-07-09 18:01:44 +00:00
|
|
|
GString *real_filter = NULL;
|
|
|
|
GString *err_msg;
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
gio->display = TRUE;
|
|
|
|
|
|
|
|
if (filter) {
|
|
|
|
/* skip all whitespaces */
|
|
|
|
while (*filter) {
|
|
|
|
if (*filter == ' ') {
|
|
|
|
filter++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*filter == '\t') {
|
|
|
|
filter++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*filter) {
|
2013-07-09 18:01:44 +00:00
|
|
|
real_filter = g_string_new("");
|
|
|
|
g_string_printf(real_filter, "(%s)", filter);
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (field) {
|
|
|
|
/* skip all whitespaces */
|
|
|
|
while (*field) {
|
|
|
|
if (*field == ' ') {
|
|
|
|
field++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*field == '\t') {
|
|
|
|
field++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*field) {
|
2013-07-09 18:01:44 +00:00
|
|
|
if (real_filter) {
|
|
|
|
g_string_append_printf(real_filter, " && (%s)", field);
|
|
|
|
} else {
|
|
|
|
real_filter = g_string_new(field);
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-09 18:01:44 +00:00
|
|
|
err_msg = register_tap_listener("frame", gio, real_filter ? real_filter->str : NULL,
|
|
|
|
TL_REQUIRES_PROTO_TREE, tap_iostat_reset, tap_iostat_packet,
|
|
|
|
tap_iostat_draw);
|
|
|
|
if (real_filter)
|
|
|
|
g_string_free(real_filter, TRUE);
|
|
|
|
return err_msg;
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
disable_graph(io_stat_graph_t *gio)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
if (gio->display) {
|
|
|
|
gio->display = FALSE;
|
|
|
|
remove_tap_listener(gio);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button),
|
|
|
|
FALSE);
|
|
|
|
}
|
Add a routine "io_stat_reset()" to reset an io_stat_t; have
"gtk_iostat_reset()" call it, and have calls to
"gtk_iostat_reset(&io->graphs[0])" just call "io_stat_reset(io)".
Add a routine "io_stat_draw()" to draw an io_stat_t; have
"gtk_iostat_draw()" call it, and have calls to
"gtk_iostat_draw(&io->graphs[0])" just call "io_stat_draw(io)".
Add a routine "io_stat_redraw()" to set the "needs_redraw" flag on an
io_stat_t and call "io_stat_draw()" on it, in order to force a redraw.
Use that in place of set flag/io_stat_draw pairs.
Add a routine "enable_graph()" to set an io_stat_graph_t's display flag
to TRUE and register a tap listener for it, and add a routine
"disable_graph()" to, if an io_stat_graph_t's display flag is set, clear
it, remove its tap listener, and turn its display button off. Use
"disable_graph()" to disable graphs, rather than just turning the
display flag off, so that we ensure that the invariant "tap listener
present iff graph enabled" is preserved - the code to destroy an io-stat
window only removes tap listeners for enabled graphs, so it depends on
that invariant being preserved.
Check the validity of a display filter by compiling it, not by going
through the whole sequence of registering a tap listener.
svn path=/trunk/; revision=9656
2004-01-13 21:04:52 +00:00
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
|
|
|
|
static void
|
2012-12-05 15:56:36 +00:00
|
|
|
iostat_init(const char *opt_arg _U_, void* userdata _U_)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_t *io;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
int i = 0;
|
2013-01-15 15:16:53 +00:00
|
|
|
static GdkColor col[MAX_GRAPHS] = {
|
|
|
|
{0, 0x0000, 0x0000, 0x0000}, /* Black */
|
|
|
|
{0, 0xffff, 0x0000, 0x0000}, /* Red */
|
|
|
|
{0, 0x0000, 0xffff, 0x0000}, /* Green */
|
|
|
|
{0, 0x0000, 0x0000, 0xffff}, /* Blue */
|
|
|
|
{0, 0xffff, 0x5000, 0xffff} /* Light brilliant magenta */
|
|
|
|
};
|
|
|
|
|
|
|
|
static GdkRGBA rgba_col[MAX_GRAPHS] = {
|
|
|
|
{0.0, 0.0, 0.0, 1.0}, /* Black */
|
|
|
|
{1.0, 0.0, 0.1, 1.0}, /* Red */
|
|
|
|
{0.0, 1.0, 0.0, 1.0}, /* Green */
|
|
|
|
{0.0, 0.0, 1.0, 1.0}, /* Blue */
|
|
|
|
{1.0, 0.314, 1.0, 1.0} /* Light brilliant magenta */
|
|
|
|
};
|
|
|
|
|
|
|
|
GString *error_string;
|
|
|
|
|
|
|
|
io = g_new(io_stat_t,1);
|
|
|
|
io->needs_redraw = TRUE;
|
|
|
|
io->interval = tick_interval_values[DEFAULT_TICK_VALUE_INDEX];
|
|
|
|
io->window = NULL;
|
|
|
|
io->draw_area = NULL;
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
io->surface = NULL;
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
io->pixmap = NULL;
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
io->scrollbar = NULL;
|
|
|
|
io->scrollbar_adjustment = NULL;
|
|
|
|
io->surface_width = 500;
|
|
|
|
io->surface_height = 200;
|
|
|
|
io->pixels_per_tick = pixels_per_tick[DEFAULT_PIXELS_PER_TICK_INDEX];
|
|
|
|
io->max_y_units = AUTO_MAX_YSCALE;
|
|
|
|
io->count_type = 0;
|
|
|
|
io->last_interval = 0xffffffff;
|
|
|
|
io->max_interval = 0;
|
|
|
|
io->num_items = 0;
|
|
|
|
io->left_x_border = 0;
|
|
|
|
io->right_x_border = 500;
|
|
|
|
io->view_as_time = FALSE;
|
|
|
|
io->start_time.secs = 0;
|
|
|
|
io->start_time.nsecs = 0;
|
|
|
|
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
io->graphs[i].color.pixel = col[i].pixel;
|
|
|
|
io->graphs[i].color.red = col[i].red;
|
|
|
|
io->graphs[i].color.green = col[i].green;
|
|
|
|
io->graphs[i].color.blue = col[i].blue;
|
|
|
|
io->graphs[i].rgba_color.red = rgba_col[i].red;
|
|
|
|
io->graphs[i].rgba_color.green = rgba_col[i].green;
|
|
|
|
io->graphs[i].rgba_color.blue = rgba_col[i].blue;
|
|
|
|
io->graphs[i].rgba_color.alpha = rgba_col[i].alpha;
|
|
|
|
io->graphs[i].display = 0;
|
|
|
|
io->graphs[i].display_button = NULL;
|
|
|
|
io->graphs[i].filter_field = NULL;
|
|
|
|
io->graphs[i].advanced_buttons = NULL;
|
|
|
|
io->graphs[i].io = io;
|
|
|
|
|
|
|
|
io->graphs[i].args = g_new(construct_args_t,1);
|
|
|
|
io->graphs[i].args->title = NULL;
|
|
|
|
io->graphs[i].args->wants_apply_button = TRUE;
|
|
|
|
io->graphs[i].args->activate_on_ok = TRUE;
|
|
|
|
io->graphs[i].args->modal_and_transient = FALSE;
|
|
|
|
|
|
|
|
io->graphs[i].filter_bt = NULL;
|
|
|
|
|
|
|
|
io->graphs[i].follow_smooth = GRAPH_FOLLOWFILTER;
|
|
|
|
}
|
|
|
|
io_stat_reset(io);
|
|
|
|
|
|
|
|
error_string = enable_graph(&io->graphs[0], NULL, NULL);
|
|
|
|
/* Can't attach io_stat tap ! */
|
|
|
|
g_assert(error_string == NULL);
|
2010-08-18 22:20:01 +00:00
|
|
|
#if 0
|
2013-01-15 15:16:53 +00:00
|
|
|
if (error_string) {
|
|
|
|
|
|
|
|
fprintf(stderr, "wireshark: Can't attach io_stat tap: %s\n",
|
|
|
|
error_string->str);
|
|
|
|
g_string_free(error_string, TRUE);
|
|
|
|
io->graphs[0].display = 0;
|
|
|
|
io->graphs[0].display_button = NULL;
|
|
|
|
io->graphs[0].filter_field = NULL;
|
|
|
|
io->graphs[0].advanced_buttons = NULL;
|
|
|
|
exit(10);
|
|
|
|
}
|
2010-08-18 22:20:01 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
/* build the GUI */
|
|
|
|
init_io_stat_window(io);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
cf_retap_packets(&cfile);
|
|
|
|
gdk_window_raise(gtk_widget_get_window(io->window));
|
|
|
|
io_stat_redraw(io);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static void
|
|
|
|
draw_area_destroy_cb(GtkWidget *widget _U_, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
int i;
|
2013-03-21 02:58:59 +00:00
|
|
|
GtkWidget *save_bt = (GtkWidget *)g_object_get_data(G_OBJECT(io->window), "save_bt");
|
|
|
|
surface_info_t *surface_info = (surface_info_t *)g_object_get_data(G_OBJECT(save_bt), "surface-info");
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
g_free(surface_info);
|
|
|
|
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
if (io->graphs[i].display) {
|
|
|
|
remove_tap_listener(&io->graphs[i]);
|
|
|
|
|
|
|
|
g_free( (gpointer) (io->graphs[i].args->title) );
|
|
|
|
io->graphs[i].args->title = NULL;
|
|
|
|
|
|
|
|
g_free(io->graphs[i].args);
|
|
|
|
io->graphs[i].args = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free(io);
|
|
|
|
|
|
|
|
return;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static gboolean
|
2012-04-01 16:01:12 +00:00
|
|
|
pixmap_clicked_event(GtkWidget *widget _U_, GdkEventButton *event, gpointer g)
|
2008-02-16 16:40:36 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)g;
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_graph_t *graph;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
io_graph_item_t *it;
|
2013-01-15 15:16:53 +00:00
|
|
|
guint32 draw_width, interval, last_interval;
|
|
|
|
guint32 frame_num = 0;
|
|
|
|
int i;
|
|
|
|
gboolean load = FALSE, outstanding_call = FALSE;
|
|
|
|
|
|
|
|
draw_width = io->surface_width - io->right_x_border - io->left_x_border;
|
|
|
|
|
|
|
|
if ((event->x <= (draw_width + io->left_x_border + 1 - (draw_width/io->pixels_per_tick)*io->pixels_per_tick)) ||
|
|
|
|
(event->x >= (draw_width + io->left_x_border - io->pixels_per_tick/2))) {
|
|
|
|
/* Outside draw area */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An interval in the IO Graph drawing area has been clicked. If left-clicked (button 1), the frame
|
|
|
|
* with the first response in that interval or if left-clicked (button 3) the last is highlighted.
|
|
|
|
*/
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
if (((event->button == 1) || (event->button == 3)) && (io->surface != NULL))
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
if (((event->button == 1) || (event->button == 3)) && (io->pixmap != NULL))
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
{
|
|
|
|
if (io->last_interval == 0xffffffff)
|
|
|
|
last_interval = io->max_interval;
|
|
|
|
else
|
|
|
|
last_interval = io->last_interval;
|
|
|
|
|
|
|
|
/* Get the interval that was clicked */
|
|
|
|
if ((last_interval / io->interval) <
|
|
|
|
((draw_width + io->left_x_border - event->x -
|
|
|
|
io->pixels_per_tick / 2 - 1) / io->pixels_per_tick)) {
|
|
|
|
interval = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
interval = (guint32) (
|
|
|
|
(last_interval / io->interval) -
|
|
|
|
((draw_width + io->left_x_border - event->x -
|
|
|
|
io->pixels_per_tick / 2 - 1) / io->pixels_per_tick));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine the lowest or highest frame number depending on whether button 1 or 3 was clicked,
|
|
|
|
* respectively, among the up to 5 currently displayed graphs. */
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
graph = &io->graphs[i];
|
|
|
|
if (graph->display) {
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
it = &graph->items[interval];
|
2013-01-15 15:16:53 +00:00
|
|
|
if (event->button == 1) {
|
|
|
|
if ((frame_num == 0) || (it->first_frame_in_invl < frame_num))
|
|
|
|
frame_num = it->first_frame_in_invl;
|
|
|
|
} else {
|
|
|
|
if (it->last_frame_in_invl > frame_num)
|
|
|
|
frame_num = it->last_frame_in_invl;
|
|
|
|
}
|
|
|
|
if (graph->calc_type == CALC_TYPE_LOAD) {
|
|
|
|
load = TRUE;
|
|
|
|
if (it->time_tot.secs + it->time_tot.nsecs > 0)
|
|
|
|
outstanding_call = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX - If the frame numbers of *calls* can somehow be determined, the first call or
|
|
|
|
* response, whichever is first, and the last call or response, whichever is last,
|
|
|
|
* could be highlighted. */
|
|
|
|
if ((frame_num == 0) && load && outstanding_call) {
|
|
|
|
statusbar_push_temporary_msg(
|
|
|
|
"There is no response but at least one call is outstanding in this interval.");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (frame_num != 0)
|
|
|
|
cf_goto_frame(&cfile, frame_num);
|
|
|
|
}
|
|
|
|
return TRUE;
|
2008-02-16 16:40:36 +00:00
|
|
|
}
|
|
|
|
|
2002-11-14 10:32:22 +00:00
|
|
|
/* create a new backing pixmap of the appropriate size */
|
2010-08-18 22:20:01 +00:00
|
|
|
static gboolean
|
|
|
|
draw_area_configure_event(GtkWidget *widget, GdkEventConfigure *event _U_, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *save_bt;
|
|
|
|
GtkAllocation widget_alloc;
|
|
|
|
cairo_t *cr;
|
2011-08-14 21:40:25 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
surface_info_t *surface_info = g_new(surface_info_t, 1);
|
2011-08-14 21:40:25 +00:00
|
|
|
#endif
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->surface) {
|
|
|
|
cairo_surface_destroy (io->surface);
|
|
|
|
io->surface = NULL;
|
|
|
|
}
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->pixmap) {
|
|
|
|
g_object_unref(io->pixmap);
|
|
|
|
io->pixmap = NULL;
|
|
|
|
}
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_widget_get_allocation(widget, &widget_alloc);
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
io->surface = gdk_window_create_similar_surface (gtk_widget_get_window(widget),
|
|
|
|
CAIRO_CONTENT_COLOR,
|
|
|
|
widget_alloc.width,
|
|
|
|
widget_alloc.height);
|
2011-08-11 20:49:07 +00:00
|
|
|
|
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
io->pixmap = gdk_pixmap_new(gtk_widget_get_window(widget),
|
|
|
|
widget_alloc.width,
|
|
|
|
widget_alloc.height,
|
|
|
|
-1);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
io->surface_width = widget_alloc.width;
|
|
|
|
io->surface_height = widget_alloc.height;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-03-21 02:58:59 +00:00
|
|
|
save_bt = (GtkWidget *)g_object_get_data(G_OBJECT(io->window), "save_bt");
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
surface_info->surface = io->surface;
|
|
|
|
surface_info->width = widget_alloc.width;
|
|
|
|
surface_info->height = widget_alloc.height;
|
|
|
|
g_object_set_data(G_OBJECT(save_bt), "surface-info", surface_info);
|
|
|
|
gtk_widget_set_sensitive(save_bt, TRUE);
|
2011-08-11 20:49:07 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
cr = cairo_create (io->surface);
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
g_object_set_data(G_OBJECT(save_bt), "pixmap", io->pixmap);
|
|
|
|
gtk_widget_set_sensitive(save_bt, TRUE);
|
2008-08-05 17:33:14 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
cr = gdk_cairo_create (io->pixmap);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_rectangle (cr, 0, 0, widget_alloc.width, widget_alloc.height);
|
|
|
|
cairo_set_source_rgb (cr, 1, 1, 1);
|
|
|
|
cairo_fill (cr);
|
|
|
|
cairo_destroy (cr);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_redraw(io);
|
|
|
|
return TRUE;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static void
|
|
|
|
scrollbar_changed(GtkWidget *widget _U_, gpointer user_data)
|
2002-11-17 11:43:40 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
guint32 mi;
|
2002-11-17 11:43:40 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
mi = (guint32) (gtk_adjustment_get_value(io->scrollbar_adjustment)
|
|
|
|
+ gtk_adjustment_get_page_size(io->scrollbar_adjustment));
|
2012-04-01 18:16:15 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
if (io->last_interval == mi) {
|
|
|
|
return;
|
|
|
|
}
|
2002-11-17 11:43:40 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io->last_interval = (mi/io->interval) * io->interval;
|
|
|
|
io_stat_redraw(io);
|
|
|
|
return;
|
2002-11-17 11:43:40 +00:00
|
|
|
}
|
2011-08-23 11:18:35 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
|
|
|
static gboolean
|
2011-08-23 13:49:37 +00:00
|
|
|
draw_area_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
|
2011-08-23 11:18:35 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkAllocation allocation;
|
2002-11-17 11:43:40 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
cairo_set_source_surface (cr, io->surface, 0, 0);
|
|
|
|
cairo_rectangle (cr, 0, 0, allocation.width, allocation.width);
|
|
|
|
cairo_fill (cr);
|
2011-08-23 11:18:35 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
return FALSE;
|
2011-08-23 11:18:35 +00:00
|
|
|
}
|
|
|
|
#else
|
2002-11-14 10:32:22 +00:00
|
|
|
/* redraw the screen from the backing pixmap */
|
2010-08-18 22:20:01 +00:00
|
|
|
static gboolean
|
|
|
|
draw_area_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_t *cr = gdk_cairo_create (gtk_widget_get_window(widget));
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2011-08-11 20:49:07 +00:00
|
|
|
#if GTK_CHECK_VERSION(2,22,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_set_source_surface (cr, io->surface, 0, 0);
|
2011-08-11 20:49:07 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
gdk_cairo_set_source_pixmap (cr, io->pixmap, 0, 0);
|
2011-08-11 20:49:07 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
|
|
|
|
cairo_fill (cr);
|
2011-07-24 11:35:51 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
cairo_destroy (cr);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
return FALSE;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
2011-08-23 11:18:35 +00:00
|
|
|
#endif
|
2002-11-29 11:37:33 +00:00
|
|
|
static void
|
2002-11-14 10:32:22 +00:00
|
|
|
create_draw_area(io_stat_t *io, GtkWidget *box)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
io->draw_area = gtk_drawing_area_new();
|
|
|
|
g_signal_connect(io->draw_area, "destroy", G_CALLBACK(draw_area_destroy_cb), io);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_widget_set_size_request(io->draw_area, io->surface_width, io->surface_height);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
/* signals needed to handle backing pixmap */
|
2011-08-23 11:18:35 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
2013-01-15 15:16:53 +00:00
|
|
|
g_signal_connect(io->draw_area, "draw", G_CALLBACK(draw_area_draw), io);
|
2011-08-23 11:18:35 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
g_signal_connect(io->draw_area, "expose-event", G_CALLBACK(draw_area_expose_event), io);
|
2011-08-23 11:18:35 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
g_signal_connect(io->draw_area, "configure-event", G_CALLBACK(draw_area_configure_event), io);
|
|
|
|
gtk_widget_add_events (io->draw_area, GDK_BUTTON_PRESS_MASK);
|
|
|
|
g_signal_connect(io->draw_area, "button-press-event", G_CALLBACK(pixmap_clicked_event), io);
|
|
|
|
|
|
|
|
gtk_widget_show(io->draw_area);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), io->draw_area, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
/* create the associated scrollbar */
|
|
|
|
io->scrollbar_adjustment = (GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
|
|
|
|
io->scrollbar = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, io->scrollbar_adjustment);
|
|
|
|
gtk_widget_show(io->scrollbar);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), io->scrollbar, FALSE, FALSE, 0);
|
|
|
|
g_signal_connect(io->scrollbar_adjustment, "value-changed", G_CALLBACK(scrollbar_changed), io);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static void
|
|
|
|
tick_interval_select(GtkWidget *item, gpointer user_data)
|
2002-11-16 11:45:58 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
int i;
|
2002-11-16 11:45:58 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
2003-10-14 09:15:51 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io->interval = tick_interval_values[i];
|
|
|
|
cf_retap_packets(&cfile);
|
|
|
|
gdk_window_raise(gtk_widget_get_window(io->window));
|
|
|
|
io_stat_redraw(io);
|
2002-11-16 11:45:58 +00:00
|
|
|
}
|
|
|
|
|
2002-11-14 10:32:22 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
pixels_per_tick_select(GtkWidget *item, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
int i;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
|
|
|
io->pixels_per_tick = pixels_per_tick[i];
|
|
|
|
io_stat_redraw(io);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2003-10-14 09:03:03 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
plot_style_select(GtkWidget *item, gpointer user_data)
|
2003-10-14 09:03:03 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *ppt = (io_stat_graph_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
int val;
|
2003-10-14 09:03:03 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
val = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
2003-10-14 09:03:03 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
ppt->plot_style = val;
|
2003-10-14 09:03:03 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_redraw(ppt->io);
|
2003-10-14 09:03:03 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 10:32:06 +00:00
|
|
|
static GtkWidget *
|
|
|
|
create_pixels_per_tick_menu_items(io_stat_t *io)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
char str[5];
|
|
|
|
GtkWidget *combo_box;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
combo_box = gtk_combo_box_text_new ();
|
|
|
|
|
|
|
|
for (i=0; i<MAX_PIXELS_PER_TICK; i++) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(str, sizeof(str), "%u", pixels_per_tick[i]);
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_PIXELS_PER_TICK_INDEX);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(pixels_per_tick_select), io);
|
|
|
|
|
|
|
|
return combo_box;
|
2009-10-16 10:32:06 +00:00
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static void
|
|
|
|
yscale_select(GtkWidget *item, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
int i;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
2003-10-14 09:55:40 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io->max_y_units = yscale_max[i];
|
|
|
|
io_stat_redraw(io);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2011-08-22 14:22:50 +00:00
|
|
|
static void
|
|
|
|
filter_select(GtkWidget *item, gpointer user_data)
|
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
i = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
|
|
|
|
|
|
|
if (i == NO_FILTER_ORDER) {
|
|
|
|
io->filter_type = NO_FILTER;
|
|
|
|
} else {
|
|
|
|
io->filter_type = MOVING_AVERAGE_FILTER;
|
|
|
|
io->filter_order = moving_average_orders[i];
|
|
|
|
}
|
|
|
|
io_stat_redraw(io);
|
2011-08-22 14:22:50 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 10:32:06 +00:00
|
|
|
static GtkWidget *
|
|
|
|
create_tick_interval_menu_items(io_stat_t *io)
|
2002-11-16 11:45:58 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *combo_box;
|
|
|
|
char str[15];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
combo_box = gtk_combo_box_text_new ();
|
|
|
|
|
|
|
|
for (i=0; i<MAX_TICK_VALUES; i++) {
|
|
|
|
if (tick_interval_values[i] >= 60000) {
|
|
|
|
g_snprintf(str, sizeof(str), "%u min", tick_interval_values[i]/60000);
|
|
|
|
} else if (tick_interval_values[i] >= 1000) {
|
|
|
|
g_snprintf(str, sizeof(str), "%u sec", tick_interval_values[i]/1000);
|
|
|
|
} else if (tick_interval_values[i] >= 100) {
|
|
|
|
g_snprintf(str, sizeof(str), "0.%1u sec", (tick_interval_values[i]/100)%10);
|
|
|
|
} else if (tick_interval_values[i] >= 10) {
|
|
|
|
g_snprintf(str, sizeof(str), "0.%02u sec", (tick_interval_values[i]/10)%10);
|
|
|
|
} else {
|
|
|
|
g_snprintf(str, sizeof(str), "0.%03u sec", (tick_interval_values[i])%10);
|
|
|
|
}
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_TICK_VALUE_INDEX);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(tick_interval_select), io);
|
|
|
|
|
|
|
|
return combo_box;
|
2002-11-16 11:45:58 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 10:32:06 +00:00
|
|
|
static GtkWidget *
|
|
|
|
create_yscale_max_menu_items(io_stat_t *io)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
char str[15];
|
|
|
|
GtkWidget *combo_box;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
combo_box = gtk_combo_box_text_new ();
|
|
|
|
for (i=0; i<MAX_YSCALE; i++) {
|
|
|
|
if (yscale_max[i] == LOGARITHMIC_YSCALE) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_strlcpy(str, "Logarithmic", sizeof(str));
|
2013-01-15 15:16:53 +00:00
|
|
|
} else if (yscale_max[i] == AUTO_MAX_YSCALE) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_strlcpy(str, "Auto", sizeof(str));
|
2013-01-15 15:16:53 +00:00
|
|
|
} else {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(str, sizeof(str), "%u", yscale_max[i]);
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_YSCALE_INDEX);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(yscale_select), io);
|
|
|
|
return combo_box;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2011-08-22 14:22:50 +00:00
|
|
|
static GtkWidget *
|
|
|
|
create_filter_menu_items(io_stat_t *io)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
char str[15];
|
|
|
|
GtkWidget *combo_box;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
combo_box = gtk_combo_box_text_new ();
|
|
|
|
|
|
|
|
for (i=0; i<MAX_MOVING_AVERAGE_ORDER; i++) {
|
|
|
|
if (i == NO_FILTER_ORDER) {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_strlcpy(str, "No filter", sizeof(str));
|
2013-01-15 15:16:53 +00:00
|
|
|
} else {
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(str, sizeof(str), "M.avg %u", moving_average_orders[i]);
|
2013-01-15 15:16:53 +00:00
|
|
|
}
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), str);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(filter_select), io);
|
|
|
|
return combo_box;
|
2011-08-22 14:22:50 +00:00
|
|
|
}
|
|
|
|
|
2002-11-14 10:32:22 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
count_type_select(GtkWidget *item, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
int i;
|
|
|
|
GtkAllocation widget_alloc;
|
|
|
|
static gboolean advanced_visible = FALSE;
|
|
|
|
|
|
|
|
io->count_type = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
|
|
|
|
|
|
|
if (io->count_type == COUNT_TYPE_ADVANCED) {
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
disable_graph(&io->graphs[i]);
|
|
|
|
gtk_widget_show(io->graphs[i].advanced_buttons);
|
|
|
|
/* redraw the entire window so the unhidden widgets show up, hopefully */
|
|
|
|
gtk_widget_get_allocation(io->window, &widget_alloc);
|
|
|
|
gtk_widget_queue_draw_area(io->window,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
widget_alloc.width,
|
|
|
|
widget_alloc.height);
|
|
|
|
}
|
|
|
|
advanced_visible = TRUE;
|
|
|
|
io_stat_redraw(io);
|
|
|
|
} else if (advanced_visible) {
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
gtk_widget_hide(io->graphs[i].advanced_buttons);
|
|
|
|
filter_callback(item, &io->graphs[i]);
|
|
|
|
}
|
|
|
|
advanced_visible = FALSE;
|
|
|
|
} else {
|
|
|
|
io_stat_redraw(io);
|
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 10:32:06 +00:00
|
|
|
static GtkWidget *
|
|
|
|
create_frames_or_bytes_menu_items(io_stat_t *io)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *combo_box;
|
|
|
|
int i;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
combo_box = gtk_combo_box_text_new ();
|
2009-10-16 10:32:06 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=0; i<MAX_COUNT_TYPES; i++) {
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), count_type_names[i]);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_COUNT_TYPE);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(count_type_select), io);
|
|
|
|
return combo_box;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2002-11-29 11:37:33 +00:00
|
|
|
static void
|
2009-10-16 10:32:06 +00:00
|
|
|
create_ctrl_menu(io_stat_t *io, GtkWidget *box, const char *name, GtkWidget * (*func)(io_stat_t *io))
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *label;
|
|
|
|
GtkWidget *combo_box;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(hbox);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
label = gtk_label_new(name);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
combo_box = (*func)(io);
|
|
|
|
gtk_box_pack_end(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(combo_box);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2007-12-29 20:57:15 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
view_as_time_toggle_dest(GtkWidget *widget _U_, gpointer user_data)
|
2007-12-29 20:57:15 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2007-12-29 20:57:15 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io->view_as_time = io->view_as_time ? FALSE : TRUE;
|
2007-12-29 20:57:15 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
io_stat_redraw(io);
|
2007-12-29 20:57:15 +00:00
|
|
|
}
|
|
|
|
|
2002-11-29 11:37:33 +00:00
|
|
|
static void
|
2002-11-14 10:32:22 +00:00
|
|
|
create_ctrl_area(io_stat_t *io, GtkWidget *box)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *frame_vbox;
|
|
|
|
GtkWidget *frame;
|
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *view_cb;
|
|
|
|
|
|
|
|
frame_vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), frame_vbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(frame_vbox);
|
|
|
|
|
|
|
|
frame = gtk_frame_new("X Axis");
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
|
|
|
|
gtk_widget_show(frame);
|
|
|
|
|
|
|
|
vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), vbox);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
create_ctrl_menu(io, vbox, "Tick interval:", create_tick_interval_menu_items);
|
|
|
|
create_ctrl_menu(io, vbox, "Pixels per tick:", create_pixels_per_tick_menu_items);
|
|
|
|
|
|
|
|
view_cb = gtk_check_button_new_with_mnemonic("_View as time of day");
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), view_cb);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(view_cb), io->view_as_time);
|
|
|
|
g_signal_connect(view_cb, "toggled", G_CALLBACK(view_as_time_toggle_dest), io);
|
|
|
|
gtk_widget_show(view_cb);
|
|
|
|
|
|
|
|
frame = gtk_frame_new("Y Axis");
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame_vbox), frame);
|
|
|
|
gtk_widget_show(frame);
|
|
|
|
|
|
|
|
vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), vbox);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
create_ctrl_menu(io, vbox, "Unit:", create_frames_or_bytes_menu_items);
|
|
|
|
create_ctrl_menu(io, vbox, "Scale:", create_yscale_max_menu_items);
|
|
|
|
create_ctrl_menu(io, vbox, "Smooth:", create_filter_menu_items);
|
|
|
|
|
|
|
|
return;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 22:20:01 +00:00
|
|
|
static void
|
2012-06-04 20:08:59 +00:00
|
|
|
filter_callback(GtkWidget *widget, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *gio = (io_stat_graph_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
const char *filter;
|
|
|
|
dfilter_t *dfilter;
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
const char *field_name = NULL;
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
/* this graph is not active, just update display and redraw */
|
|
|
|
if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gio->display_button))) {
|
|
|
|
disable_graph(gio);
|
|
|
|
io_stat_redraw(gio->io);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* first check if the field string is valid */
|
|
|
|
if (gio->io->count_type == COUNT_TYPE_ADVANCED) {
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
GString *err_str;
|
|
|
|
field_name = gtk_entry_get_text(GTK_ENTRY(gio->calc_field));
|
2013-01-15 15:16:53 +00:00
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
err_str = check_field_unit(field_name, &gio->hf_index, CALC_TYPE_TO_ITEM_UNIT(gio->calc_type));
|
|
|
|
|
|
|
|
if (err_str) {
|
|
|
|
/* warn and bail out */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str->str);
|
|
|
|
g_string_free(err_str, TRUE);
|
2013-01-15 15:16:53 +00:00
|
|
|
disable_graph(gio);
|
|
|
|
io_stat_redraw(gio->io);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
/* first check if the filter string is valid. */
|
|
|
|
filter = gtk_entry_get_text(GTK_ENTRY(gio->filter_field));
|
|
|
|
if (!dfilter_compile(filter, &dfilter)) {
|
|
|
|
bad_dfilter_alert_box(gtk_widget_get_toplevel(widget),
|
|
|
|
filter);
|
|
|
|
disable_graph(gio);
|
|
|
|
io_stat_redraw(gio->io);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (dfilter != NULL)
|
|
|
|
dfilter_free(dfilter);
|
|
|
|
|
|
|
|
/* ok, we have a valid filter and the graph is active.
|
|
|
|
first just try to delete any previous settings and then apply
|
|
|
|
the new ones.
|
|
|
|
*/
|
|
|
|
remove_tap_listener(gio);
|
|
|
|
|
|
|
|
io_stat_reset(gio->io);
|
Add a Qt I/O Graph dialog.
For each graph you can set:
- Its visibility
- A name
- A display filter
- Color, from a fixed list
- Plot style: Line, Impulse, Bar, Stacked Bar, Dot, Square, Diamond
- Basic Y Axes (packets/s, bytes/s, bits/s)
- Computed Y Axes (SUM, MIN, AVG, MAX)
- Smoothing
You can pan and zoom using the mouse and keyboard. Clicking on a graph
selects the last packet for that interval. If all graphs have the same Y
axis a single label is shown, otherwise a legend is shown.
The time scale (X axis) can be toggled between relative seconds and the
time of day.
Graphs can be saved as PDF, PNG, BMP, and JPEG. Settings are "sticky"
via the io_graphs UAT.
To do:
- Minimize graph drawing delays.
- Figure out why smoothing differs from GTK+
- Everything else at the top of io_graph_dialog.cpp
- Fix empty resets.
A fair amount of code was copied from TCPStreamDialog. We might want to
subclass QCustomPlot and place the shared code there.
Move common syntax checking to SyntaxLineEdit.
Move some common code from ui/gtk/io_stat.c to ui/io_graph_item.[ch] and
use it in both GTK+ and Qt.
Make the io_graph_item_t array allocation in io_stat.c static. The
behavior should be identical and this gives us additional compile-time
checks.
Change-Id: I9a3d544469b7048f0761fdbf7bcf20f44ae76577
Reviewed-on: https://code.wireshark.org/review/435
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Tested-by: Gerald Combs <gerald@wireshark.org>
2014-02-12 00:07:10 +00:00
|
|
|
enable_graph(gio, filter, field_name);
|
2013-01-15 15:16:53 +00:00
|
|
|
cf_retap_packets(&cfile);
|
|
|
|
gdk_window_raise(gtk_widget_get_window(gio->io->window));
|
|
|
|
io_stat_redraw(gio->io);
|
|
|
|
|
|
|
|
return;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2002-11-29 11:37:33 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
calc_type_select(GtkWidget *item, gpointer user_data)
|
2002-11-29 11:37:33 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *gio = (io_stat_graph_t *)user_data;
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
gio->calc_type = gtk_combo_box_get_active (GTK_COMBO_BOX(item));
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
/* disable the graph */
|
|
|
|
disable_graph(gio);
|
|
|
|
io_stat_redraw(gio->io);
|
2002-11-29 11:37:33 +00:00
|
|
|
}
|
|
|
|
|
2009-10-16 10:32:06 +00:00
|
|
|
static GtkWidget *
|
|
|
|
create_calc_types_menu_items(io_stat_graph_t *gio)
|
2002-11-29 11:37:33 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *combo_box;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
combo_box = gtk_combo_box_text_new ();
|
|
|
|
for (i=0; i<MAX_CALC_TYPES; i++) {
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), calc_type_names[i]);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_CALC_TYPE);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(calc_type_select), gio);
|
|
|
|
return combo_box;
|
2002-11-29 11:37:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-10-16 10:32:06 +00:00
|
|
|
create_advanced_menu(io_stat_graph_t *gio, GtkWidget *box, const char *name, GtkWidget *(*func)(io_stat_graph_t *io))
|
2002-11-29 11:37:33 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *label;
|
|
|
|
GtkWidget *combo_box;
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(hbox);
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
label = gtk_label_new(name);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
combo_box = (*func)(gio);
|
|
|
|
gtk_box_pack_end(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(combo_box);
|
2002-11-29 11:37:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_advanced_field(io_stat_graph_t *gio, GtkWidget *box)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
gio->calc_field = gtk_entry_new();
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), gio->calc_field, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show(gio->calc_field);
|
|
|
|
g_signal_connect(gio->calc_field, "activate", G_CALLBACK(filter_callback), gio);
|
|
|
|
g_object_set_data (G_OBJECT(gio->calc_field), E_FILT_FIELD_NAME_ONLY_KEY, (gpointer)"");
|
|
|
|
g_signal_connect(gio->calc_field, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
|
|
|
|
g_object_set_data(G_OBJECT(box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
|
|
|
|
g_signal_connect(gio->calc_field, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
|
|
|
|
g_signal_connect(gio->io->window, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
|
|
|
|
colorize_filter_te_as_empty(gio->calc_field);
|
2002-11-29 11:37:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_advanced_box(io_stat_graph_t *gio, GtkWidget *box)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *hbox;
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
|
|
|
|
gio->advanced_buttons = hbox;
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_hide(hbox);
|
2002-11-29 11:37:33 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
gio->calc_type = CALC_TYPE_SUM;
|
|
|
|
create_advanced_menu(gio, hbox, "Calc:", create_calc_types_menu_items);
|
|
|
|
create_advanced_field(gio, hbox);
|
2002-11-29 11:37:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
filter_button_clicked(GtkWidget *w, gpointer user_data)
|
2002-11-14 10:32:22 +00:00
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *gio = (io_stat_graph_t *)user_data;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
display_filter_construct_cb(w, gio->args);
|
|
|
|
return;
|
2003-01-11 11:10:33 +00:00
|
|
|
}
|
2002-12-16 21:18:37 +00:00
|
|
|
|
2012-12-20 13:15:20 +00:00
|
|
|
static void
|
|
|
|
smooth_filter_toggled(GtkWidget *w, gpointer user_data)
|
|
|
|
{
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_graph_t *gio = (io_stat_graph_t *)user_data;
|
2012-12-20 13:15:20 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
gio->follow_smooth =
|
|
|
|
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
|
|
|
|
io_stat_redraw(gio->io);
|
2012-12-20 13:15:20 +00:00
|
|
|
}
|
|
|
|
|
2003-01-11 11:10:33 +00:00
|
|
|
static void
|
|
|
|
create_filter_box(io_stat_graph_t *gio, GtkWidget *box, int num)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *combo_box;
|
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *label;
|
|
|
|
GtkWidget *smooth;
|
|
|
|
char str[256];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(hbox);
|
|
|
|
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(str, sizeof(str), "Graph %d", num);
|
2013-01-15 15:16:53 +00:00
|
|
|
gio->display_button = gtk_toggle_button_new_with_label(str);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), gio->display_button, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(gio->display_button);
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gio->display_button), gio->display);
|
|
|
|
g_signal_connect(gio->display_button, "toggled", G_CALLBACK(filter_callback), gio);
|
|
|
|
|
|
|
|
label = gtk_label_new("Color");
|
|
|
|
gtk_widget_show(label);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
2002-11-15 10:55:19 +00:00
|
|
|
|
2011-08-19 04:36:40 +00:00
|
|
|
#if GTK_CHECK_VERSION(3,0,0)
|
2013-03-28 06:36:44 +00:00
|
|
|
gtk_widget_override_color(label, (GtkStateFlags)GTK_STATE_FLAG_NORMAL, &gio->rgba_color);
|
2013-01-15 15:16:53 +00:00
|
|
|
/* XXX gtk_widget_override_color() takes flags not state */
|
2013-03-28 06:36:44 +00:00
|
|
|
gtk_widget_override_color(label, (GtkStateFlags)GTK_STATE_ACTIVE, &gio->rgba_color);
|
|
|
|
gtk_widget_override_color(label, (GtkStateFlags)GTK_STATE_PRELIGHT, &gio->rgba_color);
|
|
|
|
gtk_widget_override_color(label, (GtkStateFlags)GTK_STATE_SELECTED, &gio->rgba_color);
|
|
|
|
gtk_widget_override_color(label, (GtkStateFlags)GTK_STATE_INSENSITIVE, &gio->rgba_color);
|
2012-04-01 18:16:15 +00:00
|
|
|
#else
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gio->color);
|
|
|
|
gtk_widget_modify_fg(label, GTK_STATE_ACTIVE, &gio->color);
|
|
|
|
gtk_widget_modify_fg(label, GTK_STATE_PRELIGHT, &gio->color);
|
|
|
|
gtk_widget_modify_fg(label, GTK_STATE_SELECTED, &gio->color);
|
|
|
|
gtk_widget_modify_fg(label, GTK_STATE_INSENSITIVE, &gio->color);
|
2011-08-19 04:36:40 +00:00
|
|
|
#endif
|
2013-01-15 15:16:53 +00:00
|
|
|
/* g_signal_connect(gio->display_button, "toggled", G_CALLBACK(filter_callback), gio);*/
|
|
|
|
|
|
|
|
|
|
|
|
/* filter prefs dialog */
|
2014-02-21 13:09:52 +00:00
|
|
|
gio->filter_bt = ws_gtk_button_new_from_stock(WIRESHARK_STOCK_DISPLAY_FILTER_ENTRY);
|
2013-01-15 15:16:53 +00:00
|
|
|
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(str, sizeof(str), "Wireshark: Display Filter IO-Stat (Filter:%d)", num);
|
2013-01-15 15:16:53 +00:00
|
|
|
g_free( (gpointer) (gio->args->title) );
|
|
|
|
gio->args->title = g_strdup(str);
|
|
|
|
|
|
|
|
g_signal_connect(gio->filter_bt, "clicked", G_CALLBACK(filter_button_clicked), gio);
|
|
|
|
g_signal_connect(gio->filter_bt, "destroy", G_CALLBACK(filter_button_destroy_cb), NULL);
|
|
|
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), gio->filter_bt, FALSE, TRUE, 0);
|
|
|
|
gtk_widget_show(gio->filter_bt);
|
|
|
|
|
|
|
|
gio->filter_field = gtk_entry_new();
|
|
|
|
/* filter prefs dialog */
|
|
|
|
g_object_set_data(G_OBJECT(gio->filter_bt), E_FILT_TE_PTR_KEY, gio->filter_field);
|
|
|
|
/* filter prefs dialog */
|
|
|
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), gio->filter_field, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show(gio->filter_field);
|
|
|
|
g_signal_connect(gio->filter_field, "activate", G_CALLBACK(filter_callback), gio);
|
|
|
|
g_signal_connect(gio->filter_field, "changed", G_CALLBACK(filter_te_syntax_check_cb), NULL);
|
|
|
|
g_object_set_data(G_OBJECT(box), E_FILT_AUTOCOMP_PTR_KEY, NULL);
|
|
|
|
g_signal_connect(gio->filter_field, "key-press-event", G_CALLBACK (filter_string_te_key_pressed_cb), NULL);
|
|
|
|
g_signal_connect(gio->io->window, "key-press-event", G_CALLBACK (filter_parent_dlg_key_pressed_cb), NULL);
|
|
|
|
colorize_filter_te_as_empty(gio->filter_field);
|
|
|
|
|
|
|
|
create_advanced_box(gio, hbox);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create PlotStyle menu
|
|
|
|
*/
|
2013-07-09 16:58:07 +00:00
|
|
|
g_snprintf(str, sizeof(str), " Style:");
|
2013-01-15 15:16:53 +00:00
|
|
|
label = gtk_label_new(str);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
combo_box = gtk_combo_box_text_new ();
|
|
|
|
for (i=0; i<MAX_PLOT_STYLES; i++) {
|
|
|
|
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), plot_style_name[i]);
|
|
|
|
}
|
|
|
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), DEFAULT_PLOT_STYLE);
|
|
|
|
g_signal_connect(combo_box, "changed", G_CALLBACK(plot_style_select), &gio->io->graphs[num-1]);
|
|
|
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), combo_box, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(combo_box);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create smooth followfilter option
|
|
|
|
*/
|
|
|
|
smooth = gtk_check_button_new_with_mnemonic("Smooth");
|
|
|
|
gtk_widget_set_tooltip_text(smooth, "Only has effect if a smothing filter is set");
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(smooth),
|
|
|
|
gio->follow_smooth);
|
|
|
|
g_signal_connect(smooth, "toggled", G_CALLBACK(smooth_filter_toggled),
|
|
|
|
gio);
|
|
|
|
gtk_widget_show(smooth);
|
|
|
|
gtk_box_pack_end(GTK_BOX(hbox), smooth, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
return;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2002-11-29 11:37:33 +00:00
|
|
|
static void
|
2002-11-14 10:32:22 +00:00
|
|
|
create_filter_area(io_stat_t *io, GtkWidget *box)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *frame;
|
|
|
|
GtkWidget *vbox;
|
|
|
|
int i;
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
frame = gtk_frame_new("Graphs");
|
|
|
|
gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show(frame);
|
2004-02-24 23:25:28 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame), vbox);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);
|
|
|
|
gtk_widget_show(vbox);
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
create_filter_box(&io->graphs[i], vbox, i+1);
|
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
|
2013-01-15 15:16:53 +00:00
|
|
|
return;
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2008-01-20 12:24:14 +00:00
|
|
|
static void
|
2010-08-18 22:20:01 +00:00
|
|
|
copy_as_csv_cb(GtkWindow *copy_bt _U_, gpointer user_data)
|
2008-01-20 12:24:14 +00:00
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
guint32 i, interval;
|
|
|
|
guint64 val;
|
|
|
|
char string[15];
|
|
|
|
GtkClipboard *cb;
|
|
|
|
GString *CSV_str = g_string_new("");
|
2013-03-21 02:58:59 +00:00
|
|
|
io_stat_t *io = (io_stat_t *)user_data;
|
2013-01-15 15:16:53 +00:00
|
|
|
|
|
|
|
g_string_append(CSV_str, "\"Interval start\"");
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
if (io->graphs[i].display) {
|
|
|
|
g_string_append_printf(CSV_str, ",\"Graph %d\"", i+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_string_append(CSV_str,"\n");
|
|
|
|
|
|
|
|
for (interval=0; interval<io->max_interval; interval+=io->interval) {
|
2013-07-09 16:58:07 +00:00
|
|
|
print_interval_string (string, sizeof(string), interval, io, FALSE);
|
2013-01-15 15:16:53 +00:00
|
|
|
g_string_append_printf(CSV_str, "\"%s\"", string);
|
|
|
|
for (i=0; i<MAX_GRAPHS; i++) {
|
|
|
|
if (io->graphs[i].display) {
|
|
|
|
val = get_it_value(io, i, interval/io->interval);
|
|
|
|
g_string_append_printf(CSV_str, ",\"%" G_GINT64_MODIFIER "d\"", val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_string_append(CSV_str,"\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now that we have the CSV data, copy it into the default clipboard */
|
|
|
|
cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); /* Get the default clipboard */
|
|
|
|
gtk_clipboard_set_text(cb, CSV_str->str, -1); /* Copy the CSV data into the clipboard */
|
|
|
|
g_string_free(CSV_str, TRUE); /* Free the memory */
|
2008-08-05 17:33:14 +00:00
|
|
|
}
|
2008-01-20 12:24:14 +00:00
|
|
|
|
2008-08-05 17:33:14 +00:00
|
|
|
static void
|
2002-11-14 10:32:22 +00:00
|
|
|
init_io_stat_window(io_stat_t *io)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *bbox;
|
|
|
|
GtkWidget *close_bt, *help_bt;
|
|
|
|
GtkWidget *copy_bt;
|
|
|
|
GtkWidget *save_bt;
|
|
|
|
|
|
|
|
/* create the main window, transient_for top_level */
|
|
|
|
io->window = dlg_window_new("I/O Graphs");
|
|
|
|
gtk_window_set_destroy_with_parent (GTK_WINDOW(io->window), TRUE);
|
|
|
|
|
|
|
|
vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
|
|
|
|
gtk_container_add(GTK_CONTAINER(io->window), vbox);
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
create_draw_area(io, vbox);
|
|
|
|
|
|
|
|
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
|
|
|
|
gtk_widget_show(hbox);
|
|
|
|
|
|
|
|
create_filter_area(io, hbox);
|
|
|
|
create_ctrl_area(io, hbox);
|
|
|
|
|
|
|
|
io_stat_set_title(io);
|
|
|
|
|
|
|
|
bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_SAVE,
|
|
|
|
GTK_STOCK_COPY, GTK_STOCK_HELP, NULL);
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(bbox);
|
|
|
|
|
2013-03-21 02:58:59 +00:00
|
|
|
close_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
|
2013-01-15 15:16:53 +00:00
|
|
|
window_set_cancel_button(io->window, close_bt, window_cancel_button_cb);
|
|
|
|
gtk_widget_set_tooltip_text(close_bt, "Close this dialog");
|
2013-03-21 02:58:59 +00:00
|
|
|
save_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_SAVE);
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_widget_set_sensitive(save_bt, FALSE);
|
|
|
|
gtk_widget_set_tooltip_text(save_bt, "Save the displayed graph to a file");
|
|
|
|
g_signal_connect(save_bt, "clicked", G_CALLBACK(pixmap_save_cb), NULL);
|
|
|
|
g_object_set_data(G_OBJECT(io->window), "save_bt", save_bt);
|
|
|
|
|
2013-03-21 02:58:59 +00:00
|
|
|
copy_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_COPY);
|
2013-01-15 15:16:53 +00:00
|
|
|
gtk_widget_set_tooltip_text(copy_bt,
|
|
|
|
"Copy values from selected graphs to the clipboard in"
|
|
|
|
" CSV (Comma Separated Values) format");
|
|
|
|
g_signal_connect(copy_bt, "clicked", G_CALLBACK(copy_as_csv_cb), io);
|
|
|
|
|
2013-03-21 02:58:59 +00:00
|
|
|
help_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
|
2013-01-15 15:16:53 +00:00
|
|
|
g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_IO_GRAPH_DIALOG);
|
|
|
|
gtk_widget_set_tooltip_text (help_bt, "Show topic specific help");
|
|
|
|
g_signal_connect(io->window, "delete-event", G_CALLBACK(window_delete_event_cb), NULL);
|
|
|
|
|
|
|
|
gtk_widget_show(io->window);
|
|
|
|
window_present(io->window);
|
2002-11-14 10:32:22 +00:00
|
|
|
}
|
|
|
|
|
2011-05-10 05:31:45 +00:00
|
|
|
void
|
2011-05-03 16:51:08 +00:00
|
|
|
gui_iostat_cb(GtkAction *action _U_, gpointer user_data _U_)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
iostat_init(NULL,NULL);
|
2011-05-03 16:51:08 +00:00
|
|
|
}
|
2002-11-14 10:32:22 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
register_tap_listener_gtk_iostat(void)
|
|
|
|
{
|
2013-01-15 15:16:53 +00:00
|
|
|
register_stat_cmd_arg("io,stat", iostat_init,NULL);
|
2003-04-23 05:37:23 +00:00
|
|
|
}
|