crude initial start of gtk-2.0 port of pstats server

This commit is contained in:
David Rose 2006-01-17 04:04:23 +00:00
parent f71601ce86
commit d1f039f707
44 changed files with 2748 additions and 3078 deletions

View File

@ -1,27 +1,33 @@
#define BUILD_DIRECTORY $[and $[HAVE_GTKMM],$[HAVE_NET]]
#define USE_PACKAGES net gtkmm
#define BUILD_DIRECTORY $[and $[HAVE_GTK],$[HAVE_NET]]
#define USE_PACKAGES net gtk
#begin bin_target
#define TARGET gtk-stats
// We rename TARGET to gtk-pstats on Windows, so it won't compete
// with Windows-native pstats.
#define TARGET $[if $[WINDOWS_PLATFORM],gtk-pstats,pstats]
#define LOCAL_LIBS \
gtkbase progbase pstatserver
progbase pstatserver
#define OTHER_LIBS \
pstatclient:c linmath:c putil:c net:c express:c panda:m \
interrogatedb:c dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m
#define UNIX_SYS_LIBS \
m
pstatclient:c linmath:c putil:c net:c express:c pandaexpress:m panda:m \
dtoolutil:c dtoolbase:c prc:c dconfig:c dtoolconfig:m dtool:m \
pystub
#define SOURCES \
gtkStats.cxx gtkStats.h \
gtkStatsBadVersionWindow.cxx gtkStatsBadVersionWindow.h \
gtkStatsGuide.cxx gtkStatsGuide.h \
gtkStatsLabel.cxx gtkStatsLabel.h gtkStatsMainWindow.cxx \
gtkStatsMainWindow.h gtkStatsMonitor.cxx gtkStatsMonitor.h \
gtkStatsPianoRoll.I gtkStatsPianoRoll.cxx gtkStatsPianoRoll.h \
gtkStatsPianoWindow.cxx gtkStatsPianoWindow.h gtkStatsServer.cxx \
gtkStatsServer.h gtkStatsStripChart.I gtkStatsStripChart.cxx \
gtkStatsStripChart.h gtkStatsStripWindow.cxx gtkStatsStripWindow.h \
gtkStatsWindow.cxx gtkStatsWindow.h
gtkStats.cxx \
gtkStatsGraph.cxx gtkStatsGraph.h \
gtkStatsLabel.cxx gtkStatsLabel.h \
gtkStatsLabelStack.cxx gtkStatsLabelStack.h \
gtkStatsMenuId.h \
gtkStatsMonitor.cxx gtkStatsMonitor.h gtkStatsMonitor.I \
gtkStatsServer.cxx gtkStatsServer.h \
gtkStatsStripChart.cxx gtkStatsStripChart.h
// gtkStatsChartMenu.cxx gtkStatsChartMenu.h \
// gtkStatsPianoRoll.cxx gtkStatsPianoRoll.h \
#if $[DEVELOP_GTKSTATS]
#define EXTRA_CDEFS $[EXTRA_CDEFS] DEVELOP_GTKSTATS
#endif
#end bin_target

View File

@ -1,5 +1,5 @@
// Filename: gtkStats.cxx
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -16,67 +16,85 @@
//
////////////////////////////////////////////////////////////////////
#include "pandatoolbase.h"
#include "gtkStats.h"
#include "gtkStatsMainWindow.h"
#include "pStatServer.h"
#include "gtkStatsServer.h"
#include "config_pstats.h"
#include <signal.h>
GtkWidget *main_window;
static GtkStatsServer *server = NULL;
GtkStatsMainWindow *GtkStats::_main_window = NULL;
////////////////////////////////////////////////////////////////////
// Function: GtkStats::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStats::
GtkStats() {
set_program_description
("This is a fancy GUI PStats server that listens on a TCP port for a "
"connection from a PStatClient in a Panda player. It will then "
"draw strip charts illustrating the performance stats as reported "
"by the player.");
add_option
("p", "port", 0,
"Specify the TCP port to listen for connections on. By default, this "
"is taken from the pstats-host Config variable.",
&GtkStats::dispatch_int, NULL, &_port);
_port = pstats_port;
static gboolean
delete_event(GtkWidget *widget,
GdkEvent *event, gpointer data) {
// Returning FALSE to indicate we should destroy the main window
// when the user selects "close".
return FALSE;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStats::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void GtkStats::
run() {
new GtkStatsMainWindow(_port);
main_loop();
static void
destroy(GtkWidget *widget, gpointer data) {
gtk_main_quit();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStats::quit
// Access: Public, Static
// Description: Call this to cleanly shut down the program.
////////////////////////////////////////////////////////////////////
void GtkStats::
quit() {
if (_main_window != (GtkStatsMainWindow *)NULL) {
_main_window->destruct();
static gboolean
timer(gpointer data) {
server->poll();
return TRUE;
}
int
main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(main_window), "PStats");
// Connect the delete and destroy events, so the user can exit the
// application by closing the main window.
g_signal_connect(G_OBJECT(main_window), "delete_event",
G_CALLBACK(delete_event), NULL);
g_signal_connect(G_OBJECT(main_window), "destroy",
G_CALLBACK(destroy), NULL);
ostringstream stream;
stream << "Listening on port " << pstats_port;
string str = stream.str();
GtkWidget *label = gtk_label_new(str.c_str());
gtk_container_add(GTK_CONTAINER(main_window), label);
gtk_widget_show(label);
// Create the server object.
server = new GtkStatsServer;
if (!server->listen()) {
ostringstream stream;
stream
<< "Unable to open port " << pstats_port
<< ". Try specifying a different\n"
<< "port number using pstats-port in your Config file.";
string str = stream.str();
GtkWidget *dialog =
gtk_message_dialog_new(GTK_WINDOW(main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
str.c_str());
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
exit(1);
}
Gtk::Main::quit();
}
gtk_widget_show(main_window);
int main(int argc, char *argv[]) {
GtkStats prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
// Set up a timer to poll the pstats every so often.
g_timeout_add(200, timer, NULL);
// Now get lost in the message loop.
gtk_main();
return (0);
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStats.h
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -19,27 +19,11 @@
#ifndef GTKSTATS_H
#define GTKSTATS_H
#include "pandatoolbase.h"
#include "pStatServer.h"
#include "gtkBase.h"
#include <gtk/gtk.h>
class GtkStatsMainWindow;
////////////////////////////////////////////////////////////////////
// Class : GtkStats
// Description : A fancy graphical pstats server written using gtk+
// (actually, Gtk--, the C++ layer over gtk+).
////////////////////////////////////////////////////////////////////
class GtkStats : public GtkBase {
public:
GtkStats();
void run();
static void quit();
int _port;
static GtkStatsMainWindow *_main_window;
};
extern GtkWidget *main_window;
#endif

View File

@ -1,73 +0,0 @@
// Filename: gtkStatsBadVersionWindow.cxx
// Created by: drose (18May01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsBadVersionWindow.h"
#include "gtkStatsMonitor.h"
#include "string_utils.h"
////////////////////////////////////////////////////////////////////
// Function: GtkStatsBadVersionWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsBadVersionWindow::
GtkStatsBadVersionWindow(GtkStatsMonitor *monitor,
int client_major, int client_minor,
int server_major, int server_minor) {
set_title("Bad client");
Gtk::VBox *box1 = new Gtk::VBox;
box1->show();
box1->set_border_width(8);
add(*manage(box1));
string message =
"Rejected connection by " +
monitor->get_client_progname() + " from " +
monitor->get_client_hostname() + ".\nClient uses PStats version " +
format_string(client_major) + "." + format_string(client_minor) +
",\nwhile server expects PStats version " +
format_string(server_major) + "." + format_string(server_minor) + ".";
Gtk::Label *label = new Gtk::Label(message);
label->show();
box1->pack_start(*manage(label), true, false, 8);
Gtk::HBox *box2 = new Gtk::HBox;
box2->show();
box1->pack_start(*manage(box2), false, false, 0);
Gtk::Button *close = new Gtk::Button("Close");
close->set_usize(80, 30);
close->show();
box2->pack_start(*manage(close), true, false, 0);
close->clicked.connect(slot(this, &GtkStatsBadVersionWindow::close_clicked));
setup();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsBadVersionWindow::close_clicked
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsBadVersionWindow::
close_clicked() {
destruct();
}

View File

@ -1,45 +0,0 @@
// Filename: gtkStatsBadVersionWindow.h
// Created by: drose (18May01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSBADVERSIONWINDOW_H
#define GTKSTATSBADVERSIONWINDOW_H
#include "pandatoolbase.h"
#include "basicGtkWindow.h"
class GtkStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsBadVersionWindow
// Description : This window is popped up to indicated an attempted
// connection from an invalid client.
////////////////////////////////////////////////////////////////////
class GtkStatsBadVersionWindow : public BasicGtkWindow {
public:
GtkStatsBadVersionWindow(GtkStatsMonitor *monitor,
int client_major, int client_minor,
int server_major, int server_minor);
private:
void close_clicked();
};
#endif

View File

@ -0,0 +1,209 @@
// Filename: gtkStatsChartMenu.cxx
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsChartMenu.h"
#include "gtkStatsMonitor.h"
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsChartMenu::
GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index) :
_monitor(monitor),
_thread_index(thread_index)
{
_menu = CreatePopupMenu();
do_update();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsChartMenu::
~GtkStatsChartMenu() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::get_menu_handle
// Access: Public
// Description: Returns the Windows menu handle for this particular
// menu.
////////////////////////////////////////////////////////////////////
HMENU GtkStatsChartMenu::
get_menu_handle() {
return _menu;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::add_to_menu_bar
// Access: Public
// Description: Adds the menu to the end of the indicated menu bar.
////////////////////////////////////////////////////////////////////
void GtkStatsChartMenu::
add_to_menu_bar(HMENU menu_bar, int before_menu_id) {
const PStatClientData *client_data = _monitor->get_client_data();
string thread_name;
if (_thread_index == 0) {
// A special case for the main thread.
thread_name = "Graphs";
} else {
thread_name = client_data->get_thread_name(_thread_index);
}
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
mii.fType = MFT_STRING;
mii.hSubMenu = _menu;
mii.dwTypeData = (char *)thread_name.c_str();
InsertMenuItem(menu_bar, before_menu_id, FALSE, &mii);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::check_update
// Access: Public
// Description: Checks to see if the menu needs to be updated
// (e.g. because of new data from the client), and
// updates it if necessary.
////////////////////////////////////////////////////////////////////
void GtkStatsChartMenu::
check_update() {
PStatView &view = _monitor->get_view(_thread_index);
if (view.get_level_index() != _last_level_index) {
do_update();
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::do_update
// Access: Public
// Description: Unconditionally updates the menu with the latest data
// from the client.
////////////////////////////////////////////////////////////////////
void GtkStatsChartMenu::
do_update() {
PStatView &view = _monitor->get_view(_thread_index);
_last_level_index = view.get_level_index();
// First, remove all of the old entries from the menu.
int num_items = GetMenuItemCount(_menu);
for (int i = num_items - 1; i >= 0; i--) {
DeleteMenu(_menu, i, MF_BYPOSITION);
}
// Now rebuild the menu with the new set of entries.
// The menu item(s) for the thread's frame time goes first.
add_view(_menu, view.get_top_level(), false);
bool needs_separator = true;
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
// And then the menu item(s) for each of the level values.
const PStatClientData *client_data = _monitor->get_client_data();
int num_toplevel_collectors = client_data->get_num_toplevel_collectors();
for (int tc = 0; tc < num_toplevel_collectors; tc++) {
int collector = client_data->get_toplevel_collector(tc);
if (client_data->has_collector(collector) &&
client_data->get_collector_has_level(collector)) {
// We put a separator between the above frame collector and the
// first level collector.
if (needs_separator) {
mii.fMask = MIIM_FTYPE;
mii.fType = MFT_SEPARATOR;
InsertMenuItem(_menu, GetMenuItemCount(_menu), TRUE, &mii);
needs_separator = false;
}
PStatView &level_view = _monitor->get_level_view(collector, _thread_index);
add_view(_menu, level_view.get_top_level(), true);
}
}
// Also a menu item for a piano roll (following a separator).
mii.fMask = MIIM_FTYPE;
mii.fType = MFT_SEPARATOR;
InsertMenuItem(_menu, GetMenuItemCount(_menu), TRUE, &mii);
GtkStatsMonitor::MenuDef menu_def(_thread_index, -1, false);
int menu_id = _monitor->get_menu_id(menu_def);
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
mii.fType = MFT_STRING;
mii.wID = menu_id;
mii.dwTypeData = "Piano Roll";
InsertMenuItem(_menu, GetMenuItemCount(_menu), TRUE, &mii);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsChartMenu::add_view
// Access: Private
// Description: Adds a new entry or entries to the menu for the
// indicated view and its children.
////////////////////////////////////////////////////////////////////
void GtkStatsChartMenu::
add_view(HMENU parent_menu, const PStatViewLevel *view_level, bool show_level) {
int collector = view_level->get_collector();
const PStatClientData *client_data = _monitor->get_client_data();
string collector_name = client_data->get_collector_name(collector);
GtkStatsMonitor::MenuDef menu_def(_thread_index, collector, show_level);
int menu_id = _monitor->get_menu_id(menu_def);
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
mii.fType = MFT_STRING;
mii.wID = menu_id;
mii.dwTypeData = (char *)collector_name.c_str();
InsertMenuItem(parent_menu, GetMenuItemCount(parent_menu), TRUE, &mii);
int num_children = view_level->get_num_children();
if (num_children > 1) {
// If the collector has more than one child, add a menu entry to go
// directly to each of its children.
HMENU submenu = CreatePopupMenu();
string submenu_name = collector_name + " components";
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
mii.fType = MFT_STRING;
mii.hSubMenu = submenu;
mii.dwTypeData = (char *)submenu_name.c_str();
InsertMenuItem(parent_menu, GetMenuItemCount(parent_menu), TRUE, &mii);
// Reverse the order since the menus are listed from the top down;
// we want to be visually consistent with the graphs, which list
// these labels from the bottom up.
for (int c = num_children - 1; c >= 0; c--) {
add_view(submenu, view_level->get_child(c), show_level);
}
}
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsPianoWindow.h
// Created by: drose (18Jul00)
// Filename: gtkStatsChartMenu.h
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -16,42 +16,43 @@
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSPIANOWINDOW_H
#define GTKSTATSPIANOWINDOW_H
#ifndef GTKSTATSCHARTMENU_H
#define GTKSTATSCHARTMENU_H
#include "pandatoolbase.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsWindow.h"
#include <windows.h>
class GtkStatsPianoRoll;
class GtkStatsMonitor;
class PStatView;
class PStatViewLevel;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsPianoWindow
// Description : A window that contains a GtkStatsPianoRoll.
// Class : GtkStatsChartMenu
// Description : A pulldown menu of charts available for a particular
// thread.
////////////////////////////////////////////////////////////////////
class GtkStatsPianoWindow : public GtkStatsWindow {
class GtkStatsChartMenu {
public:
GtkStatsPianoWindow(GtkStatsMonitor *monitor, int thread_index,
int chart_xsize, int chart_ysize);
GtkStatsChartMenu(GtkStatsMonitor *monitor, int thread_index);
~GtkStatsChartMenu();
virtual void mark_dead();
virtual void idle();
HMENU get_menu_handle();
void add_to_menu_bar(HMENU menu_bar, int before_menu_id);
protected:
virtual void setup_menu();
virtual void menu_new_window();
void menu_hscale(float hz);
void check_update();
void do_update();
private:
void layout_window(int chart_xsize, int chart_ysize);
void add_view(HMENU parent_menu, const PStatViewLevel *view_level,
bool show_level);
private:
GtkStatsMonitor *_monitor;
int _thread_index;
GtkStatsPianoRoll *_chart;
int _last_level_index;
HMENU _menu;
};
#endif

View File

@ -0,0 +1,395 @@
// Filename: gtkStatsGraph.cxx
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsGraph.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsLabelStack.h"
const GdkColor GtkStatsGraph::rgb_white = {
0, 0xffff, 0xffff, 0xffff
};
const GdkColor GtkStatsGraph::rgb_light_gray = {
0, 0x9a9a, 0x9a9a, 0x9a9a,
};
const GdkColor GtkStatsGraph::rgb_dark_gray = {
0, 0x3333, 0x3333, 0x3333,
};
const GdkColor GtkStatsGraph::rgb_black = {
0, 0x0000, 0x0000, 0x0000
};
const GdkColor GtkStatsGraph::rgb_user_guide_bar = {
0, 0x8282, 0x9696, 0xffff
};
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsGraph::
GtkStatsGraph(GtkStatsMonitor *monitor, int thread_index) :
_monitor(monitor),
_thread_index(thread_index)
{
_parent_window = NULL;
_window = NULL;
_graph_window = NULL;
// _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE);
// _hand_cursor = LoadCursor(NULL, IDC_HAND);
_pixmap = 0;
_pixmap_gc = 0;
_graph_left = 0;
_graph_top = 0;
_pixmap_xsize = 0;
_pixmap_ysize = 0;
_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget *parent_window = monitor->get_window();
gtk_window_set_transient_for(GTK_WINDOW(_window), GTK_WINDOW(parent_window));
gtk_window_set_destroy_with_parent(GTK_WINDOW(_window), TRUE);
g_signal_connect(G_OBJECT(_window), "delete_event",
G_CALLBACK(window_delete_event), this);
g_signal_connect(G_OBJECT(_window), "destroy",
G_CALLBACK(window_destroy), this);
_graph_window = gtk_drawing_area_new();
g_signal_connect(G_OBJECT(_graph_window), "expose_event",
G_CALLBACK(expose_event_callback), this);
g_signal_connect(G_OBJECT(_graph_window), "configure_event",
G_CALLBACK(configure_event_callback), this);
gtk_widget_set_size_request(_graph_window, 400, 100);
_drag_mode = DM_none;
_potential_drag_mode = DM_none;
_drag_scale_start = 0.0f;
_pause = false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsGraph::
~GtkStatsGraph() {
_monitor = (GtkStatsMonitor *)NULL;
release_pixmap();
/*
DeleteObject(_dark_pen);
DeleteObject(_light_pen);
DeleteObject(_user_guide_bar_pen);
*/
Brushes::iterator bi;
for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) {
GdkGC *gc = (*bi).second;
g_object_unref(gc);
}
if (_graph_window != NULL) {
gtk_widget_destroy(_graph_window);
_graph_window = NULL;
}
if (_window != NULL) {
gtk_widget_destroy(_window);
_window = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::get_thread_index
// Access: Public
// Description: Returns the thread index associated with this
// particular graph.
////////////////////////////////////////////////////////////////////
int GtkStatsGraph::
get_thread_index() const {
return _thread_index;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::new_collector
// Access: Public, Virtual
// Description: Called whenever a new Collector definition is
// received from the client.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
new_collector(int new_collector) {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::new_data
// Access: Public, Virtual
// Description: Called whenever new data arrives.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
new_data(int thread_index, int frame_number) {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::force_redraw
// Access: Public, Virtual
// Description: Called when it is necessary to redraw the entire graph.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
force_redraw() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::changed_graph_size
// Access: Public, Virtual
// Description: Called when the user has resized the window, forcing
// a resize of the graph.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
changed_graph_size(int graph_xsize, int graph_ysize) {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::set_time_units
// Access: Public, Virtual
// Description: Called when the user selects a new time units from
// the monitor pulldown menu, this should adjust the
// units for the graph to the indicated mask if it is a
// time-based graph.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
set_time_units(int unit_mask) {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::set_scroll_speed
// Access: Public
// Description: Called when the user selects a new scroll speed from
// the monitor pulldown menu, this should adjust the
// speed for the graph to the indicated value.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
set_scroll_speed(float scroll_speed) {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::set_pause
// Access: Public
// Description: Changes the pause flag for the graph. When this flag
// is true, the graph does not update in response to new
// data.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
set_pause(bool pause) {
_pause = pause;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::user_guide_bars_changed
// Access: Public
// Description: Called when the user guide bars have been changed.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
user_guide_bars_changed() {
/*
InvalidateRect(_window, NULL, TRUE);
InvalidateRect(_graph_window, NULL, TRUE);
*/
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::clicked_label
// Access: Public, Virtual
// Description: Called when the user single-clicks on a label.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
clicked_label(int collector_index) {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::close
// Access: Protected
// Description: Should be called when the user closes the associated
// window. This tells the monitor to remove the graph.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
close() {
GtkStatsMonitor *monitor = _monitor;
_monitor = (GtkStatsMonitor *)NULL;
if (monitor != (GtkStatsMonitor *)NULL) {
monitor->remove_graph(this);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::get_collector_gc
// Access: Protected
// Description: Returns a GC suitable for drawing in the indicated
// collector's color.
////////////////////////////////////////////////////////////////////
GdkGC *GtkStatsGraph::
get_collector_gc(int collector_index) {
Brushes::iterator bi;
bi = _brushes.find(collector_index);
if (bi != _brushes.end()) {
return (*bi).second;
}
// Ask the monitor what color this guy should be.
RGBColorf rgb = _monitor->get_collector_color(collector_index);
GdkColor c;
c.red = (int)(rgb[0] * 65535.0f);
c.green = (int)(rgb[1] * 65535.0f);
c.blue = (int)(rgb[2] * 65535.0f);
GdkGC *gc = gdk_gc_new(_pixmap);
g_object_ref(gc);
gdk_gc_set_rgb_fg_color(gc, &c);
_brushes[collector_index] = gc;
return gc;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::consider_drag_start
// Access: Protected, Virtual
// Description: Based on the mouse position within the window's
// client area, look for draggable things the mouse
// might be hovering over and return the apprioprate
// DragMode enum or DM_none if nothing is indicated.
////////////////////////////////////////////////////////////////////
GtkStatsGraph::DragMode GtkStatsGraph::
consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
if (mouse_x >= _left_margin - 2 && mouse_x <= _left_margin + 2) {
return DM_left_margin;
} else if (mouse_x >= width - _right_margin - 2 && mouse_x <= width - _right_margin + 2) {
return DM_right_margin;
}
return DM_none;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::set_drag_mode
// Access: Protected, Virtual
// Description: This should be called whenever the drag mode needs to
// change state. It provides hooks for a derived class
// to do something special.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
set_drag_mode(GtkStatsGraph::DragMode drag_mode) {
_drag_mode = drag_mode;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::setup_pixmap
// Access: Private
// Description: Sets up a backing-store bitmap of the indicated size.
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
setup_pixmap(int xsize, int ysize) {
release_pixmap();
_pixmap_xsize = max(xsize, 0);
_pixmap_ysize = max(ysize, 0);
_pixmap = gdk_pixmap_new(_graph_window->window, _pixmap_xsize, _pixmap_ysize, -1);
g_object_ref(_pixmap);
_pixmap_gc = gdk_gc_new(_pixmap);
g_object_ref(_pixmap_gc);
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0,
_pixmap_xsize, _pixmap_ysize);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::release_pixmap
// Access: Private
// Description: Frees the backing-store bitmap created by
// setup_pixmap().
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
release_pixmap() {
if (_pixmap != NULL) {
g_object_unref(_pixmap);
g_object_unref(_pixmap_gc);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::window_delete_event
// Access: Private, Static
// Description: Callback when the window is closed by the user.
////////////////////////////////////////////////////////////////////
gboolean GtkStatsGraph::
window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
// Returning FALSE to indicate we should destroy the window
// when the user selects "close".
return FALSE;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::window_delete_event
// Access: Private, Static
// Description: Callback when the window is destroyed by the system
// (or by delete_event).
////////////////////////////////////////////////////////////////////
void GtkStatsGraph::
window_destroy(GtkWidget *widget, gpointer data) {
GtkStatsGraph *self = (GtkStatsGraph *)data;
self->close();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::expose_event_callback
// Access: Private, Static
// Description: Fills in the graph window.
////////////////////////////////////////////////////////////////////
gboolean GtkStatsGraph::
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
GtkStatsGraph *self = (GtkStatsGraph *)data;
if (self->_pixmap != NULL) {
gdk_draw_drawable(self->_graph_window->window,
self->_graph_window->style->fg_gc[0],
self->_pixmap, 0, 0, 0, 0,
self->_pixmap_xsize, self->_pixmap_ysize);
}
return TRUE;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGraph::configure_event_callback
// Access: Private, Static
// Description: Changes the size of the graph window
////////////////////////////////////////////////////////////////////
gboolean GtkStatsGraph::
configure_event_callback(GtkWidget *widget, GdkEventConfigure *event,
gpointer data) {
GtkStatsGraph *self = (GtkStatsGraph *)data;
self->changed_graph_size(event->width, event->height);
self->setup_pixmap(event->width, event->height);
self->force_redraw();
return TRUE;
}

View File

@ -0,0 +1,142 @@
// Filename: gtkStatsGraph.h
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSGRAPH_H
#define GTKSTATSGRAPH_H
#include "pandatoolbase.h"
#include "gtkStatsLabelStack.h"
#include "pmap.h"
#include <gtk/gtk.h>
class GtkStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsGraph
// Description : This is just an abstract base class to provide a
// common pointer type for the various kinds of graphs
// that may be created for a GtkStatsMonitor.
////////////////////////////////////////////////////////////////////
class GtkStatsGraph {
public:
// What is the user adjusting by dragging the mouse in a window?
enum DragMode {
DM_none,
DM_scale,
DM_left_margin,
DM_right_margin,
DM_guide_bar,
DM_new_guide_bar,
DM_sizing,
};
public:
GtkStatsGraph(GtkStatsMonitor *monitor, int thread_index);
virtual ~GtkStatsGraph();
int get_thread_index() const;
virtual void new_collector(int collector_index);
virtual void new_data(int thread_index, int frame_number);
virtual void force_redraw();
virtual void changed_graph_size(int graph_xsize, int graph_ysize);
virtual void set_time_units(int unit_mask);
virtual void set_scroll_speed(float scroll_speed);
void set_pause(bool pause);
void user_guide_bars_changed();
virtual void clicked_label(int collector_index);
protected:
void close();
GdkGC *get_collector_gc(int collector_index);
/*
virtual void additional_window_paint(HDC hdc);
virtual void additional_graph_window_paint(HDC hdc);
*/
virtual DragMode consider_drag_start(int mouse_x, int mouse_y,
int width, int height);
virtual void set_drag_mode(DragMode drag_mode);
protected:
// Table of GC's for our various collectors.
typedef pmap<int, GdkGC *> Brushes;
Brushes _brushes;
GtkStatsMonitor *_monitor;
int _thread_index;
GtkWidget *_parent_window;
GtkWidget *_window;
GtkWidget *_graph_window;
GtkStatsLabelStack _label_stack;
/*
HCURSOR _sizewe_cursor;
HCURSOR _hand_cursor;
*/
GdkPixmap *_pixmap;
GdkGC *_pixmap_gc;
int _graph_left, _graph_top;
int _pixmap_xsize, _pixmap_ysize;
int _left_margin, _right_margin;
int _top_margin, _bottom_margin;
/*
COLORREF _dark_color;
COLORREF _light_color;
COLORREF _user_guide_bar_color;
HPEN _dark_pen;
HPEN _light_pen;
HPEN _user_guide_bar_pen;
*/
DragMode _drag_mode;
DragMode _potential_drag_mode;
int _drag_start_x, _drag_start_y;
float _drag_scale_start;
int _drag_guide_bar;
bool _pause;
static const GdkColor rgb_white;
static const GdkColor rgb_light_gray;
static const GdkColor rgb_dark_gray;
static const GdkColor rgb_black;
static const GdkColor rgb_user_guide_bar;
private:
void setup_pixmap(int xsize, int ysize);
void release_pixmap();
void create_graph_window();
static gboolean window_delete_event(GtkWidget *widget, GdkEvent *event,
gpointer data);
static void window_destroy(GtkWidget *widget, gpointer data);
static gboolean expose_event_callback(GtkWidget *widget,
GdkEventExpose *event, gpointer data);
static gboolean configure_event_callback(GtkWidget *widget,
GdkEventConfigure *event, gpointer data);
};
#endif

View File

@ -1,88 +0,0 @@
// Filename: gtkStatsGuide.cxx
// Created by: drose (16Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsGuide.h"
#include "pStatStripChart.h"
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGuide::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsGuide::
GtkStatsGuide(PStatStripChart *chart) :
_chart(chart)
{
set_events(GDK_EXPOSURE_MASK);
// Choose a suitable minimum width. This requires knowing what the
// font will be.
Gdk_Font font = get_style()->gtkobj()->font;
int text_width = font.string_width("0000");
set_usize(text_width, 0);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGuide::configure_event_impl
// Access: Private, Virtual
// Description: Creates a new backing pixmap of the appropriate size.
////////////////////////////////////////////////////////////////////
gint GtkStatsGuide::
configure_event_impl(GdkEventConfigure *) {
Gdk_Window window = get_window();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsGuide::expose_event_impl
// Access: Private, Virtual
// Description: Redraw the text. We don't bother with clipping
// regions here, but just draw the whole thing every
// time.
////////////////////////////////////////////////////////////////////
gint GtkStatsGuide::
expose_event_impl(GdkEventExpose *event) {
Gdk_GC fg_gc =
get_style()->gtkobj()->fg_gc[GTK_WIDGET_STATE (GTK_WIDGET(gtkobj()))];
Gdk_GC bg_gc =
get_style()->gtkobj()->bg_gc[GTK_WIDGET_STATE (GTK_WIDGET(gtkobj()))];
if (fg_gc && bg_gc) {
Gdk_Window window = get_window();
window.draw_rectangle(bg_gc, true, 0, 0, width(), height());
Gdk_Font font = fg_gc.get_font();
int text_ascent = font.ascent();
int num_guide_bars = _chart->get_num_guide_bars();
for (int i = 0; i < num_guide_bars; i++) {
const PStatStripChart::GuideBar &bar = _chart->get_guide_bar(i);
int y = _chart->height_to_pixel(bar._height);
if (y >= 5) {
// Only draw it if it's not too close to the top.
window.draw_string(font, fg_gc, 0, y + text_ascent / 2,
bar._label);
}
}
}
return false;
}

View File

@ -1,47 +0,0 @@
// Filename: gtkStatsGuide.h
// Created by: drose (16Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSGUIDE_H
#define GTKSTATSGUIDE_H
#include "pandatoolbase.h"
#include <gtk--.h>
class PStatStripChart;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsGuide
// Description : A widget designed to be drawn next to a
// GtkStatsStripChart that shows the labels associated
// with the strip chart's guide bars.
////////////////////////////////////////////////////////////////////
class GtkStatsGuide : public Gtk::DrawingArea {
public:
GtkStatsGuide(PStatStripChart *chart);
private:
virtual gint configure_event_impl(GdkEventConfigure *event);
virtual gint expose_event_impl(GdkEventExpose *event);
private:
PStatStripChart *_chart;
};
#endif

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsLabel.cxx
// Created by: drose (15Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -18,27 +18,40 @@
#include "gtkStatsLabel.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsGraph.h"
#include "pStatClientData.h"
#include "pStatMonitor.h"
int GtkStatsLabel::_left_margin = 2;
int GtkStatsLabel::_right_margin = 2;
int GtkStatsLabel::_top_margin = 2;
int GtkStatsLabel::_bottom_margin = 2;
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::Constructor
// Access: Public
// Description: This constructor automatically figures out the
// appropriate name and color for the label.
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsLabel::
GtkStatsLabel(PStatMonitor *monitor, int collector_index,
Gdk_Font font) :
_collector_index(collector_index),
_font(font)
GtkStatsLabel(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
int thread_index, int collector_index, bool use_fullname) :
_monitor(monitor),
_graph(graph),
_thread_index(thread_index),
_collector_index(collector_index)
{
set_events(GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
_widget = NULL;
if (use_fullname) {
_text = _monitor->get_client_data()->get_collector_fullname(_collector_index);
} else {
_text = _monitor->get_client_data()->get_collector_name(_collector_index);
}
_text = monitor->get_client_data()->get_collector_name(_collector_index);
RGBColorf rgb = monitor->get_collector_color(_collector_index);
_bg_color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
/*
RGBColorf rgb = _monitor->get_collector_color(_collector_index);
int r = (int)(rgb[0] * 255.0f);
int g = (int)(rgb[1] * 255.0f);
int b = (int)(rgb[2] * 255.0f);
_bg_color = RGB(r, g, b);
_bg_brush = CreateSolidBrush(RGB(r, g, b));
// Should our foreground be black or white?
float bright =
@ -47,96 +60,103 @@ GtkStatsLabel(PStatMonitor *monitor, int collector_index,
rgb[2] * 0.114;
if (bright >= 0.5) {
_fg_color.set_rgb_p(0, 0, 0);
_fg_color = RGB(0, 0, 0);
_highlight_brush = (HBRUSH)GetStockObject(BLACK_BRUSH);
} else {
_fg_color.set_rgb_p(1, 1, 1);
_fg_color = RGB(255, 255, 255);
_highlight_brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
}
*/
Gdk_Colormap::get_system().alloc(_fg_color);
Gdk_Colormap::get_system().alloc(_bg_color);
int text_width = _font.string_width(_text);
int text_height = _font.height();
_height = text_height + 4;
_width = text_width + 4;
set_usize(_width, _height);
_highlight = false;
_mouse_within = false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::get_width
// Function: GtkStatsLabel::Destructor
// Access: Public
// Description: Returns the width of the widget as we requested it.
////////////////////////////////////////////////////////////////////
int GtkStatsLabel::
get_width() const {
return _width;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::get_height
// Access: Public
// Description: Returns the height of the widget as we requested it.
////////////////////////////////////////////////////////////////////
int GtkStatsLabel::
get_height() const {
return _height;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::configure_event_impl
// Access: Private, Virtual
// Description: Creates a new backing pixmap of the appropriate size.
////////////////////////////////////////////////////////////////////
gint GtkStatsLabel::
configure_event_impl(GdkEventConfigure *) {
Gdk_Window window = get_window();
_gc = Gdk_GC(window);
_gc.set_foreground(_fg_color);
_gc.set_background(_bg_color);
_gc.set_font(_font);
_reverse_gc = Gdk_GC(window);
_reverse_gc.set_foreground(_bg_color);
_reverse_gc.set_background(_fg_color);
_reverse_gc.set_font(_font);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::expose_event_impl
// Access: Private, Virtual
// Description: Redraw the text. We don't bother with clipping
// regions here, but just draw the whole text every
// time.
////////////////////////////////////////////////////////////////////
gint GtkStatsLabel::
expose_event_impl(GdkEventExpose *event) {
int text_width = _font.string_width(_text);
int text_height = _font.height();
Gdk_Window window = get_window();
window.draw_rectangle(_reverse_gc, true, 0, 0, width(), height());
window.draw_string(_font, _gc, width() - text_width - 2,
height() - (height() - text_height) / 2 - _font.descent(),
_text);
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::button_press_event_impl
// Access: Private, Virtual
// Description:
////////////////////////////////////////////////////////////////////
gint GtkStatsLabel::
button_press_event_impl(GdkEventButton *button) {
if (button->type == GDK_2BUTTON_PRESS && button->button == 1) {
collector_picked(_collector_index);
return true;
}
return false;
GtkStatsLabel::
~GtkStatsLabel() {
// DeleteObject(_bg_brush);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::setup
// Access: Public
// Description: Creates the actual widget.
////////////////////////////////////////////////////////////////////
GtkWidget *GtkStatsLabel::
setup() {
_widget = gtk_event_box_new();
GtkWidget *label = gtk_label_new(_text.c_str());
gtk_container_add(GTK_CONTAINER(_widget), label);
gtk_widget_show(label);
gtk_widget_show(_widget);
return _widget;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::get_widget
// Access: Public
// Description: Returns the widget for this label.
////////////////////////////////////////////////////////////////////
GtkWidget *GtkStatsLabel::
get_widget() const {
return _widget;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::get_collector_index
// Access: Public
// Description: Returns the collector this label represents.
////////////////////////////////////////////////////////////////////
int GtkStatsLabel::
get_collector_index() const {
return _collector_index;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::set_highlight
// Access: Public
// Description: Enables or disables the visual highlight for this
// label.
////////////////////////////////////////////////////////////////////
void GtkStatsLabel::
set_highlight(bool highlight) {
if (_highlight != highlight) {
_highlight = highlight;
/*
InvalidateRect(_widget, NULL, TRUE);
*/
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::get_highlight
// Access: Public
// Description: Returns true if the visual highlight for this
// label is enabled.
////////////////////////////////////////////////////////////////////
bool GtkStatsLabel::
get_highlight() const {
return _highlight;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabel::set_mouse_within
// Access: Private
// Description: Used internally to indicate whether the mouse is
// within the label's widget.
////////////////////////////////////////////////////////////////////
void GtkStatsLabel::
set_mouse_within(bool mouse_within) {
if (_mouse_within != mouse_within) {
_mouse_within = mouse_within;
/*
InvalidateRect(_widget, NULL, TRUE);
*/
}
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsLabel.h
// Created by: drose (15Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -21,47 +21,54 @@
#include "pandatoolbase.h"
#include <gtk--.h>
#include <gtk/gtk.h>
class PStatMonitor;
class GtkStatsMonitor;
class GtkStatsGraph;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsLabel
// Description : A text label that will draw in color appropriate for
// a particular collector, instead of referring to some
// dumb Gtk::Style. It also throws a signal when the
// user double-clicks on it, passing in the collector
// index. This is handy for putting colored labels on
// strip charts.
// a particular collector. It also responds when the
// user double-clicks on it. This is handy for putting
// colored labels on strip charts.
////////////////////////////////////////////////////////////////////
class GtkStatsLabel : public Gtk::DrawingArea {
class GtkStatsLabel {
public:
GtkStatsLabel(PStatMonitor *monitor, int collector_index,
Gdk_Font font);
GtkStatsLabel(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
int thread_index, int collector_index, bool use_fullname);
~GtkStatsLabel();
int get_width() const;
int get_height() const;
GtkWidget *setup();
GtkWidget *get_widget() const;
SigC::Signal1<void, int> collector_picked;
int get_collector_index() const;
void set_highlight(bool highlight);
bool get_highlight() const;
private:
virtual gint configure_event_impl (GdkEventConfigure *event);
virtual gint expose_event_impl (GdkEventExpose *event);
virtual gint button_press_event_impl(GdkEventButton *button);
void set_mouse_within(bool mouse_within);
private:
GtkStatsMonitor *_monitor;
GtkStatsGraph *_graph;
int _thread_index;
int _collector_index;
string _text;
Gdk_Font _font;
Gdk_Color _fg_color;
Gdk_Color _bg_color;
GtkWidget *_widget;
int _width;
int _height;
/*
COLORREF _bg_color;
COLORREF _fg_color;
HBRUSH _bg_brush;
HBRUSH _highlight_brush;
*/
Gdk_GC _gc;
Gdk_GC _reverse_gc;
bool _highlight;
bool _mouse_within;
static int _left_margin, _right_margin;
static int _top_margin, _bottom_margin;
};
#endif

View File

@ -0,0 +1,147 @@
// Filename: gtkStatsLabelStack.cxx
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsLabelStack.h"
#include "gtkStatsLabel.h"
#include "notify.h"
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsLabelStack::
GtkStatsLabelStack() {
_widget = NULL;
_highlight_label = -1;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsLabelStack::
~GtkStatsLabelStack() {
clear_labels();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::setup
// Access: Public
// Description: Creates the actual widget object.
////////////////////////////////////////////////////////////////////
GtkWidget *GtkStatsLabelStack::
setup() {
if (_widget == NULL) {
_widget = gtk_vbox_new(FALSE, 0);
}
return _widget;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::is_setup
// Access: Public
// Description: Returns true if the label stack has been set up,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool GtkStatsLabelStack::
is_setup() const {
return (_widget != NULL);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::get_label_collector_index
// Access: Public
// Description: Returns the collector index associated with the
// indicated label.
////////////////////////////////////////////////////////////////////
int GtkStatsLabelStack::
get_label_collector_index(int label_index) const {
nassertr(label_index >= 0 && label_index < (int)_labels.size(), -1);
return _labels[label_index]->get_collector_index();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::clear_labels
// Access: Public
// Description: Removes the set of labels and starts a new set.
////////////////////////////////////////////////////////////////////
void GtkStatsLabelStack::
clear_labels() {
Labels::iterator li;
for (li = _labels.begin(); li != _labels.end(); ++li) {
GtkStatsLabel *label = (*li);
gtk_container_remove(GTK_CONTAINER(_widget), label->get_widget());
delete (*li);
}
_labels.clear();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::add_label
// Access: Public
// Description: Adds a new label to the top of the stack; returns the
// new label index.
////////////////////////////////////////////////////////////////////
int GtkStatsLabelStack::
add_label(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
int thread_index, int collector_index, bool use_fullname) {
GtkStatsLabel *label =
new GtkStatsLabel(monitor, graph, thread_index, collector_index, use_fullname);
gtk_box_pack_start(GTK_BOX(_widget), label->setup(),
FALSE, FALSE, 0);
int label_index = (int)_labels.size();
_labels.push_back(label);
return label_index;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::get_num_labels
// Access: Public
// Description: Returns the number of labels in the stack.
////////////////////////////////////////////////////////////////////
int GtkStatsLabelStack::
get_num_labels() const {
return _labels.size();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsLabelStack::highlight_label
// Access: Public
// Description: Draws a highlight around the label representing the
// indicated collector, and removes the highlight from
// any other label. Specify -1 to remove the highlight
// from all labels.
////////////////////////////////////////////////////////////////////
void GtkStatsLabelStack::
highlight_label(int collector_index) {
if (_highlight_label != collector_index) {
_highlight_label = collector_index;
Labels::iterator li;
for (li = _labels.begin(); li != _labels.end(); ++li) {
GtkStatsLabel *label = (*li);
label->set_highlight(label->get_collector_index() == _highlight_label);
}
}
}

View File

@ -0,0 +1,62 @@
// Filename: gtkStatsLabelStack.h
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSLABELSTACK_H
#define GTKSTATSLABELSTACK_H
#include "pandatoolbase.h"
#include "pvector.h"
#include <gtk/gtk.h>
class GtkStatsLabel;
class GtkStatsMonitor;
class GtkStatsGraph;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsLabelStack
// Description : A widget that contains a stack of labels from bottom
// to top.
////////////////////////////////////////////////////////////////////
class GtkStatsLabelStack {
public:
GtkStatsLabelStack();
~GtkStatsLabelStack();
GtkWidget *setup();
bool is_setup() const;
int get_label_collector_index(int label_index) const;
void clear_labels();
int add_label(GtkStatsMonitor *monitor, GtkStatsGraph *graph,
int thread_index, int collector_index, bool use_fullname);
int get_num_labels() const;
void highlight_label(int collector_index);
private:
GtkWidget *_widget;
int _highlight_label;
typedef pvector<GtkStatsLabel *> Labels;
Labels _labels;
};
#endif

View File

@ -1,141 +0,0 @@
// Filename: gtkStatsMainWindow.cxx
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsMainWindow.h"
#include "gtkStats.h"
#include "gtkStatsServer.h"
#include "string_utils.h"
#include <signal.h>
static bool user_interrupted = false;
// This simple signal handler lets us know when the user has pressed
// control-C, so we can clean up nicely.
static void signal_handler(int) {
user_interrupted = true;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMainWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsMainWindow::
GtkStatsMainWindow(int port) : _port(port) {
nassertv(GtkStats::_main_window == (GtkStatsMainWindow *)NULL);
GtkStats::_main_window = this;
// Set up a global signal handler to catch Interrupt (Control-C) so
// we can clean up nicely if the user stops us.
signal(SIGINT, &signal_handler);
_server = new GtkStatsServer;
if (!_server->listen(_port)) {
nout << "Unable to open port.\n";
exit(1);
}
layout_window();
setup();
Gtk::Main::timeout.
connect(slot(this, &GtkStatsMainWindow::idle_callback), 200);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMainWindow::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsMainWindow::
~GtkStatsMainWindow() {
nassertv(GtkStats::_main_window == this);
GtkStats::_main_window = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMainWindow::destruct
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool GtkStatsMainWindow::
destruct() {
if (BasicGtkWindow::destruct()) {
nassertr(_server != (GtkStatsServer *)NULL, false);
delete _server;
GtkStats::quit();
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMainWindow::layout_window
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsMainWindow::
layout_window() {
set_title("Gtk Stats");
Gtk::VBox *box1 = new Gtk::VBox;
box1->show();
box1->set_border_width(8);
add(*manage(box1));
Gtk::Label *listening =
new Gtk::Label("Listening on port " + format_string(_port));
listening->show();
box1->pack_start(*manage(listening), true, false, 8);
Gtk::HBox *box2 = new Gtk::HBox;
box2->show();
box1->pack_start(*manage(box2), false, false, 0);
Gtk::Button *close = new Gtk::Button("Close");
close->set_usize(80, 30);
close->show();
box2->pack_start(*manage(close), true, false, 0);
close->clicked.connect(slot(this, &GtkStatsMainWindow::close_clicked));
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMainWindow::close_clicked
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsMainWindow::
close_clicked() {
destruct();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMainWindow::idle_callback
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
gint GtkStatsMainWindow::
idle_callback() {
if (user_interrupted) {
destruct();
return false;
}
_server->poll();
return true;
}

View File

@ -1,51 +0,0 @@
// Filename: gtkStatsMainWindow.h
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSMAINWINDOW_H
#define GTKSTATSMAINWINDOW_H
#include "pandatoolbase.h"
#include "basicGtkWindow.h"
class GtkStatsServer;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsMainWindow
// Description : This is the main window that's opened up and stays up
// all the time when you run gtk-stats. It just shows
// that it's running.
////////////////////////////////////////////////////////////////////
class GtkStatsMainWindow : public BasicGtkWindow {
public:
GtkStatsMainWindow(int port);
virtual ~GtkStatsMainWindow();
virtual bool destruct();
private:
void layout_window();
void close_clicked();
gint idle_callback();
int _port;
GtkStatsServer *_server;
};
#endif

View File

@ -1,5 +1,5 @@
// Filename: gtkBase.h
// Created by: drose (14Jul00)
// Filename: gtkStatsMenuId.h
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -16,32 +16,32 @@
//
////////////////////////////////////////////////////////////////////
#ifndef GTKBASE_H
#define GTKBASE_H
#ifndef GTKSTATSMENUID_H
#define GTKSTATSMENUID_H
#include "pandatoolbase.h"
#include "programBase.h"
#include <gtk--.h>
////////////////////////////////////////////////////////////////////
// Class : GtkBase
// Description : This is a specialization of ProgramBase for programs
// that use the Gtk-- GUI toolkit.
// Enum : GtkStatsMenuId
// Description : The enumerated values here are used for menu ID's for
// the various pulldown menus in the application.
////////////////////////////////////////////////////////////////////
class GtkBase : public ProgramBase {
public:
GtkBase();
~GtkBase();
enum GtkStatsMenuId {
MI_none,
MI_time_ms,
MI_time_hz,
MI_frame_rate_label,
MI_speed_1,
MI_speed_2,
MI_speed_3,
MI_speed_6,
MI_speed_12,
MI_pause,
virtual void parse_command_line(int argc, char *argv[]);
void main_loop();
public:
static Gtk::Main *_gtk;
// This one is last and represents the beginning of the range for
// the various "new chart" menu options.
MI_new_chart
};
#endif

View File

@ -0,0 +1,47 @@
// Filename: gtkStatsMonitor.I
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::MenuDef::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsMonitor::MenuDef::
MenuDef(int thread_index, int collector_index, bool show_level) :
_thread_index(thread_index),
_collector_index(collector_index),
_show_level(show_level)
{
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::MenuDef::operator <
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool GtkStatsMonitor::MenuDef::
operator < (const MenuDef &other) const {
if (_thread_index != other._thread_index) {
return _thread_index < other._thread_index;
}
if (_collector_index != other._collector_index) {
return _collector_index < other._collector_index;
}
return (int)_show_level < (int)other._show_level;
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsMonitor.cxx
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -17,15 +17,36 @@
////////////////////////////////////////////////////////////////////
#include "gtkStatsMonitor.h"
#include "gtkStatsWindow.h"
#include "gtkStatsStripWindow.h"
#include "gtkStatsBadVersionWindow.h"
#include "gtkStats.h"
#include "gtkStatsServer.h"
#include "luse.h"
#include "gtkStatsStripChart.h"
/*
#include "gtkStatsPianoRoll.h"
#include "gtkStatsChartMenu.h"
*/
#include "gtkStatsMenuId.h"
#include "pStatGraph.h"
#include "pStatCollectorDef.h"
#include "indent.h"
typedef void vc();
GtkItemFactoryEntry GtkStatsMonitor::menu_entries[] = {
{ "/Options", NULL, NULL, 0, "<Branch>" },
{ "/Options/Units", NULL, NULL, 0, "<Branch>" },
{ "/Options/Units/ms", NULL, (vc *)&handle_menu_command, MI_time_ms, "<RadioItem>" },
{ "/Options/Units/Hz", NULL, (vc *)&handle_menu_command, MI_time_hz, "/Options/Units/ms" },
{ "/Speed", NULL, NULL, 0, "<Branch>" },
{ "/Speed/1", NULL, (vc *)&handle_menu_command, MI_speed_1, "<RadioItem>" },
{ "/Speed/2", NULL, (vc *)&handle_menu_command, MI_speed_2, "/Speed/1" },
{ "/Speed/3", NULL, (vc *)&handle_menu_command, MI_speed_3, "/Speed/1" },
{ "/Speed/6", NULL, (vc *)&handle_menu_command, MI_speed_6, "/Speed/1" },
{ "/Speed/12", NULL, (vc *)&handle_menu_command, MI_speed_12, "/Speed/1" },
{ "/Speed/sep", NULL, NULL, 0, "<Separator>" },
{ "/Speed/pause", NULL, (vc *)&handle_menu_command, MI_pause, "<CheckItem>" },
};
int GtkStatsMonitor::num_menu_entries = sizeof(menu_entries) / sizeof(GtkItemFactoryEntry);
#include <gdk--.h>
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::Constructor
@ -34,44 +55,45 @@
////////////////////////////////////////////////////////////////////
GtkStatsMonitor::
GtkStatsMonitor(GtkStatsServer *server) : PStatMonitor(server) {
_destructing = false;
_new_collector = false;
_window = NULL;
_item_factory = NULL;
// These will be filled in later when the menu is created.
_time_units = 0;
_scroll_speed = 0.0;
_pause = false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::Destructor
// Access: Public
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsMonitor::
~GtkStatsMonitor() {
_destructing = true;
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
GtkStatsWindow *window = (*wi);
window->destruct();
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
delete (*gi);
}
}
_graphs.clear();
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::close_all_windows
// Access: Public
// Description: Closes all the windows associated with this client.
// This returns a PointerTo itself, just to guarantee
// that the monitor won't destruct until the function
// returns (as it might, if there were no other pointers
// to it).
////////////////////////////////////////////////////////////////////
PT(PStatMonitor) GtkStatsMonitor::
close_all_windows() {
PT(PStatMonitor) temp = this;
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
GtkStatsWindow *window = (*wi);
window->destruct();
/*
ChartMenus::iterator mi;
for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
delete (*mi);
}
return temp;
_chart_menus.clear();
*/
if (_window != NULL) {
gtk_widget_destroy(_window);
_window = NULL;
}
#ifdef DEVELOP_GTKSTATS
// For Gtkstats developers, exit when the first monitor closes.
gtk_main_quit(0);
#endif
}
////////////////////////////////////////////////////////////////////
@ -82,7 +104,7 @@ close_all_windows() {
////////////////////////////////////////////////////////////////////
string GtkStatsMonitor::
get_monitor_name() {
return "Gtk Stats";
return "GtkStats";
}
////////////////////////////////////////////////////////////////////
@ -98,8 +120,6 @@ get_monitor_name() {
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
initialized() {
// Create a default window: a strip chart for the main thread.
new GtkStatsStripWindow(this, 0, 0, false, 400, 100);
}
////////////////////////////////////////////////////////////////////
@ -111,10 +131,8 @@ initialized() {
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
got_hello() {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
(*wi)->update_title();
}
create_window();
open_strip_chart(0, 0, false);
}
////////////////////////////////////////////////////////////////////
@ -131,9 +149,29 @@ got_hello() {
void GtkStatsMonitor::
got_bad_version(int client_major, int client_minor,
int server_major, int server_minor) {
new GtkStatsBadVersionWindow(this, client_major, client_minor,
server_major, server_minor);
close_all_windows();
ostringstream str;
str << "Unable to honor connection attempt from "
<< get_client_progname() << " on " << get_client_hostname()
<< ": unsupported PStats version "
<< client_major << "." << client_minor;
if (server_minor == 0) {
str << " (server understands version " << server_major
<< "." << server_minor << " only).";
} else {
str << " (server understands versions " << server_major
<< ".0 through " << server_major << "." << server_minor << ").";
}
string message = str.str();
GtkWidget *dialog =
gtk_message_dialog_new(GTK_WINDOW(main_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
message.c_str());
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
////////////////////////////////////////////////////////////////////
@ -148,8 +186,41 @@ got_bad_version(int client_major, int client_minor,
// definitions midstream.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
new_collector(int) {
_new_collector = true;
new_collector(int collector_index) {
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
GtkStatsGraph *graph = (*gi);
graph->new_collector(collector_index);
}
/*
// We might need to update our menus.
ChartMenus::iterator mi;
for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
(*mi)->do_update();
}
*/
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::new_thread
// Access: Public, Virtual
// Description: Called whenever a new Thread definition is
// received from the client. Generally, the client will
// send all of its threads over shortly after
// connecting, but there's no guarantee that they will
// all be received before the first frames are received.
// The monitor should be prepared to accept new Thread
// definitions midstream.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
new_thread(int thread_index) {
/*
GtkStatsChartMenu *chart_menu = new GtkStatsChartMenu(this, thread_index);
chart_menu->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
_chart_menus.push_back(chart_menu);
DrawMenuBar(_window);
*/
}
////////////////////////////////////////////////////////////////////
@ -163,6 +234,11 @@ new_collector(int) {
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
new_data(int thread_index, int frame_number) {
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
GtkStatsGraph *graph = (*gi);
graph->new_data(thread_index, frame_number);
}
}
@ -176,9 +252,11 @@ new_data(int thread_index, int frame_number) {
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
lost_connection() {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
(*wi)->mark_dead();
nout << "Lost connection to " << get_client_hostname() << "\n";
if (_window != NULL) {
gtk_widget_destroy(_window);
_window = NULL;
}
}
@ -191,11 +269,29 @@ lost_connection() {
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
idle() {
Windows::iterator wi;
for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
(*wi)->idle();
/*
// Check if any of our chart menus need updating.
ChartMenus::iterator mi;
for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
(*mi)->check_update();
}
_new_collector = false;
// Update the frame rate label from the main thread (thread 0).
const PStatThreadData *thread_data = get_client_data()->get_thread_data(0);
float frame_rate = thread_data->get_frame_rate();
if (frame_rate != 0.0f) {
char buffer[128];
sprintf(buffer, "%0.1f ms / %0.1f Hz", 1000.0f / frame_rate, frame_rate);
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STRING;
mii.dwTypeData = buffer;
SetMenuItemInfo(_menu_bar, MI_frame_rate_label, FALSE, &mii);
DrawMenuBar(_window);
}
*/
}
////////////////////////////////////////////////////////////////////
@ -210,52 +306,339 @@ has_idle() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::is_thread_safe
// Function: GtkStatsMonitor::user_guide_bars_changed
// Access: Public, Virtual
// Description: Should be redefined to return true if this monitor
// class can handle running in a sub-thread.
//
// This is not related to the question of whether it can
// handle multiple different PStatThreadDatas; this is
// strictly a question of whether or not the monitor
// itself wants to run in a sub-thread.
// Description: Called when the user guide bars have been changed.
////////////////////////////////////////////////////////////////////
bool GtkStatsMonitor::
is_thread_safe() {
return true;
void GtkStatsMonitor::
user_guide_bars_changed() {
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
GtkStatsGraph *graph = (*gi);
graph->user_guide_bars_changed();
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::add_window
// Function: GtkStatsMonitor::get_window
// Access: Public
// Description: Called only from the GtkStatsWindow constructor, this
// indicates a new window that we should track.
// Description: Returns the window handle to the monitor's window.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
add_window(GtkStatsWindow *window) {
nassertv(!_destructing);
bool inserted = _windows.insert(window).second;
nassertv(inserted);
GtkWidget *GtkStatsMonitor::
get_window() const {
return _window;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::remove_window
// Function: GtkStatsMonitor::open_strip_chart
// Access: Public
// Description: Called only from the GtkStatsWindow destructor, this
// indicates the end of a window that we should now no
// longer track.
//
// When the last window is deleted, this automatically
// closes the connection.
// Description: Opens a new strip chart showing the indicated data.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
remove_window(GtkStatsWindow *window) {
if (!_destructing) {
bool removed = (_windows.erase(window) != 0);
nassertv(removed);
open_strip_chart(int thread_index, int collector_index, bool show_level) {
GtkStatsStripChart *graph =
new GtkStatsStripChart(this, thread_index, collector_index, show_level);
add_graph(graph);
if (_windows.empty()) {
close();
graph->set_time_units(_time_units);
graph->set_scroll_speed(_scroll_speed);
graph->set_pause(_pause);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::open_piano_roll
// Access: Public
// Description: Opens a new piano roll showing the indicated data.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
open_piano_roll(int thread_index) {
/*
GtkStatsPianoRoll *graph = new GtkStatsPianoRoll(this, thread_index);
add_graph(graph);
graph->set_time_units(_time_units);
graph->set_scroll_speed(_scroll_speed);
graph->set_pause(_pause);
*/
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::lookup_menu
// Access: Public
// Description: Returns the MenuDef properties associated with the
// indicated menu ID. This specifies what we expect to
// do when the given menu has been selected.
////////////////////////////////////////////////////////////////////
const GtkStatsMonitor::MenuDef &GtkStatsMonitor::
lookup_menu(int menu_id) const {
static MenuDef invalid(0, 0, false);
int menu_index = menu_id - MI_new_chart;
nassertr(menu_index >= 0 && menu_index < (int)_menu_by_id.size(), invalid);
return _menu_by_id[menu_index];
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::get_menu_id
// Access: Public
// Description: Returns the menu ID that is reserved for the
// indicated MenuDef properties. If this is the first
// time these particular properties have been requested,
// a new menu ID is returned; otherwise, the existing
// menu ID is returned.
////////////////////////////////////////////////////////////////////
int GtkStatsMonitor::
get_menu_id(const MenuDef &menu_def) {
MenuByDef::iterator mi;
mi = _menu_by_def.find(menu_def);
if (mi != _menu_by_def.end()) {
return (*mi).second;
}
// Slot a new id.
int menu_id = (int)_menu_by_id.size() + MI_new_chart;
_menu_by_id.push_back(menu_def);
_menu_by_def[menu_def] = menu_id;
return menu_id;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::set_time_units
// Access: Public
// Description: Called when the user selects a new time units from
// the monitor pulldown menu, this should adjust the
// units for all graphs to the indicated mask if it is a
// time-based graph.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
set_time_units(int unit_mask) {
_time_units = unit_mask;
// First, change all of the open graphs appropriately.
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
GtkStatsGraph *graph = (*gi);
graph->set_time_units(_time_units);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::set_scroll_speed
// Access: Public
// Description: Called when the user selects a new scroll speed from
// the monitor pulldown menu, this should adjust the
// speeds for all graphs to the indicated value.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
set_scroll_speed(float scroll_speed) {
_scroll_speed = scroll_speed;
// First, change all of the open graphs appropriately.
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
GtkStatsGraph *graph = (*gi);
graph->set_scroll_speed(_scroll_speed);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::set_pause
// Access: Public
// Description: Called when the user selects a pause on or pause off
// option from the menu.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
set_pause(bool pause) {
_pause = pause;
// First, change all of the open graphs appropriately.
Graphs::iterator gi;
for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
GtkStatsGraph *graph = (*gi);
graph->set_pause(_pause);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::add_graph
// Access: Private
// Description: Adds the newly-created graph to the list of managed
// graphs.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
add_graph(GtkStatsGraph *graph) {
_graphs.insert(graph);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::remove_graph
// Access: Private
// Description: Deletes the indicated graph.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
remove_graph(GtkStatsGraph *graph) {
Graphs::iterator gi = _graphs.find(graph);
if (gi != _graphs.end()) {
_graphs.erase(gi);
delete graph;
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::create_window
// Access: Private
// Description: Creates the window for this monitor.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
create_window() {
if (_window != NULL) {
return;
}
_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(_window), "delete_event",
G_CALLBACK(window_delete_event), this);
g_signal_connect(G_OBJECT(_window), "destroy",
G_CALLBACK(window_destroy), this);
_window_title = get_client_progname() + " on " + get_client_hostname();
gtk_window_set_title(GTK_WINDOW(_window), _window_title.c_str());
gtk_window_set_default_size(GTK_WINDOW(_window), 500, 360);
// Set up the menu.
GtkAccelGroup *accel_group = gtk_accel_group_new();
_item_factory =
gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<PStats>", accel_group);
gtk_item_factory_create_items(_item_factory, num_menu_entries, menu_entries,
this);
gtk_window_add_accel_group(GTK_WINDOW(_window), accel_group);
GtkWidget *menubar = gtk_item_factory_get_widget(_item_factory, "<PStats>");
/*
ChartMenus::iterator mi;
for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
(*mi)->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
}
*/
// Pack the menu into the window.
GtkWidget *main_vbox = gtk_vbox_new(FALSE, 1);
// gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
gtk_container_add(GTK_CONTAINER(_window), main_vbox);
gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
gtk_widget_show_all(_window);
gtk_widget_show(_window);
set_time_units(PStatGraph::GBU_ms);
set_scroll_speed(3);
set_pause(false);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::window_delete_event
// Access: Private, Static
// Description: Callback when the window is closed by the user.
////////////////////////////////////////////////////////////////////
gboolean GtkStatsMonitor::
window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) {
// Returning FALSE to indicate we should destroy the window
// when the user selects "close".
return FALSE;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::window_delete_event
// Access: Private, Static
// Description: Callback when the window is destroyed by the system
// (or by delete_event).
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
window_destroy(GtkWidget *widget, gpointer data) {
GtkStatsMonitor *self = (GtkStatsMonitor *)data;
self->close();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::setup_frame_rate_label
// Access: Private
// Description: Creates the frame rate label on the right end of the
// menu bar. This is used as a text label to display
// the main thread's frame rate to the user, although it
// is implemented as a right-justified toplevel menu
// item that doesn't open to anything.
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
setup_frame_rate_label() {
/*
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
mii.fType = MFT_STRING | MFT_RIGHTJUSTIFY;
mii.wID = MI_frame_rate_label;
mii.dwTypeData = "";
InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
*/
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsMonitor::handle_menu_command
// Access: Private, Static
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsMonitor::
handle_menu_command(gpointer callback_data, guint menu_id, GtkWidget *widget) {
GtkStatsMonitor *self = (GtkStatsMonitor *)callback_data;
switch (menu_id) {
case MI_none:
break;
case MI_time_ms:
self->set_time_units(PStatGraph::GBU_ms);
break;
case MI_time_hz:
self->set_time_units(PStatGraph::GBU_hz);
break;
case MI_speed_1:
self->set_scroll_speed(1);
break;
case MI_speed_2:
self->set_scroll_speed(2);
break;
case MI_speed_3:
self->set_scroll_speed(3);
break;
case MI_speed_6:
self->set_scroll_speed(6);
break;
case MI_speed_12:
self->set_scroll_speed(12);
break;
case MI_pause:
self->set_pause(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
break;
default:
if (menu_id >= MI_new_chart) {
const MenuDef &menu_def = self->lookup_menu(menu_id);
if (menu_def._collector_index < 0) {
self->open_piano_roll(menu_def._thread_index);
} else {
self->open_strip_chart(menu_def._thread_index,
menu_def._collector_index,
menu_def._show_level);
}
}
}
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsMonitor.h
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -21,25 +21,37 @@
#include "pandatoolbase.h"
#include "gtkStatsGraph.h"
#include "pStatMonitor.h"
#include "pointerTo.h"
#include "pset.h"
#include "pvector.h"
#include "pmap.h"
#include <gtk/gtk.h>
class GtkStatsServer;
class GtkStatsWindow;
class Gdk_Color;
class GtkStatsChartMenu;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsMonitor
// Description :
// Description : This class represents a connection to a PStatsClient
// and manages the data exchange with the client.
////////////////////////////////////////////////////////////////////
class GtkStatsMonitor : public PStatMonitor {
public:
GtkStatsMonitor(GtkStatsServer *server);
~GtkStatsMonitor();
class MenuDef {
public:
INLINE MenuDef(int thread_index, int collector_index, bool show_level);
INLINE bool operator < (const MenuDef &other) const;
PT(PStatMonitor) close_all_windows();
int _thread_index;
int _collector_index;
bool _show_level;
};
GtkStatsMonitor(GtkStatsServer *server);
virtual ~GtkStatsMonitor();
virtual string get_monitor_name();
@ -48,21 +60,61 @@ public:
virtual void got_bad_version(int client_major, int client_minor,
int server_major, int server_minor);
virtual void new_collector(int collector_index);
virtual void new_thread(int thread_index);
virtual void new_data(int thread_index, int frame_number);
virtual void lost_connection();
virtual void idle();
virtual bool has_idle();
virtual bool is_thread_safe();
public:
void add_window(GtkStatsWindow *window);
void remove_window(GtkStatsWindow *window);
virtual void user_guide_bars_changed();
typedef pset<GtkStatsWindow *> Windows;
Windows _windows;
GtkWidget *get_window() const;
void open_strip_chart(int thread_index, int collector_index, bool show_level);
void open_piano_roll(int thread_index);
bool _destructing;
bool _new_collector;
const MenuDef &lookup_menu(int menu_id) const;
int get_menu_id(const MenuDef &menu_def);
void set_time_units(int unit_mask);
void set_scroll_speed(float scroll_speed);
void set_pause(bool pause);
private:
void add_graph(GtkStatsGraph *graph);
void remove_graph(GtkStatsGraph *graph);
void create_window();
static gboolean window_delete_event(GtkWidget *widget, GdkEvent *event,
gpointer data);
static void window_destroy(GtkWidget *widget, gpointer data);
void setup_frame_rate_label();
static void handle_menu_command(gpointer callback_data, guint menu_id, GtkWidget *widget);
typedef pset<GtkStatsGraph *> Graphs;
Graphs _graphs;
typedef pvector<GtkStatsChartMenu *> ChartMenus;
ChartMenus _chart_menus;
typedef pvector<MenuDef> MenuById;
typedef pmap<MenuDef, int> MenuByDef;
MenuById _menu_by_id;
MenuByDef _menu_by_def;
GtkWidget *_window;
GtkItemFactory *_item_factory;
string _window_title;
int _time_units;
float _scroll_speed;
bool _pause;
static GtkItemFactoryEntry menu_entries[];
static int num_menu_entries;
friend class GtkStatsGraph;
};
#include "gtkStatsMonitor.I"
#endif

View File

@ -1,17 +0,0 @@
// Filename: gtkStatsPianoRoll.I
// Created by: drose (18Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsPianoRoll.cxx
// Created by: drose (18Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -17,16 +17,14 @@
////////////////////////////////////////////////////////////////////
#include "gtkStatsPianoRoll.h"
#include "gtkStatsLabel.h"
#include "gtkStatsGuide.h"
#include "gtkStatsMonitor.h"
#include "numeric_types.h"
#include "request_initial_size.h"
#include "pStatThreadData.h"
#include "pStatFrameData.h"
#include "pStatView.h"
#include <algorithm>
static const int default_piano_roll_width = 400;
static const int default_piano_roll_height = 200;
bool GtkStatsPianoRoll::_window_class_registered = false;
const char * const GtkStatsPianoRoll::_window_class_name = "piano";
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::Constructor
@ -34,115 +32,147 @@
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsPianoRoll::
GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index,
int xsize, int ysize) :
PStatPianoRoll(monitor, thread_index, xsize, ysize)
GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index) :
PStatPianoRoll(monitor, thread_index,
default_piano_roll_width,
default_piano_roll_height),
GtkStatsGraph(monitor, thread_index)
{
_is_dead = false;
set_events(GDK_EXPOSURE_MASK);
_left_margin = 128;
_right_margin = 8;
_top_margin = 16;
_bottom_margin = 8;
_label_align = manage(new Gtk::Alignment(1.0, 1.0));
_label_align->show();
// Let's show the units on the guide bar labels. There's room.
set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
_label_box = NULL;
pack_labels();
request_initial_size(*this, get_xsize(), get_ysize());
create_window();
clear_region();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::mark_dead
// Access: Public
// Description: Called when the client's connection has been lost,
// this should update the window in some obvious way to
// indicate that the window is no longer live.
// Function: GtkStatsPianoRoll::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsPianoRoll::
~GtkStatsPianoRoll() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::idle
// Access: Public, Virtual
// Description: Called as each frame's data is made available. There
// is no gurantee the frames will arrive in order, or
// that all of them will arrive at all. The monitor
// should be prepared to accept frames received
// out-of-order or missing.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
mark_dead() {
_is_dead = true;
setup_white_gc();
force_redraw();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::get_labels
// Access: Public
// Description: Returns an alignment widget that contains all of the
// labels appropriate to this chart, already formatted
// and stacked up bottom-to-top. The window should pack
// this widget suitably near the strip chart.
////////////////////////////////////////////////////////////////////
Gtk::Alignment *GtkStatsPianoRoll::
get_labels() {
return _label_align;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::get_collector_gc
// Access: Public
// Description: Returns a graphics context suitable for drawing in
// the indicated collector's color.
////////////////////////////////////////////////////////////////////
Gdk_GC GtkStatsPianoRoll::
get_collector_gc(int collector_index) {
GCs::iterator gi;
gi = _gcs.find(collector_index);
if (gi != _gcs.end()) {
return (*gi).second;
new_data(int thread_index, int frame_number) {
if (!_pause) {
update();
}
}
// Ask the monitor what color this guy should be.
RGBColorf rgb = get_monitor()->get_collector_color(collector_index);
Gdk_Color color;
color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::force_redraw
// Access: Public, Virtual
// Description: Called when it is necessary to redraw the entire graph.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
force_redraw() {
PStatPianoRoll::force_redraw();
}
// Now allocate the color from the system colormap.
Gdk_Colormap::get_system().alloc(color);
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::changed_graph_size
// Access: Public, Virtual
// Description: Called when the user has resized the window, forcing
// a resize of the graph.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
changed_graph_size(int graph_xsize, int graph_ysize) {
PStatPianoRoll::changed_size(graph_xsize, graph_ysize);
}
// Allocate a new graphics context.
Gdk_GC gc(_pixmap);
gc.set_foreground(color);
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::set_time_units
// Access: Public, Virtual
// Description: Called when the user selects a new time units from
// the monitor pulldown menu, this should adjust the
// units for the graph to the indicated mask if it is a
// time-based graph.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
set_time_units(int unit_mask) {
int old_unit_mask = get_guide_bar_units();
if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
unit_mask = unit_mask & (GBU_hz | GBU_ms);
unit_mask |= (old_unit_mask & GBU_show_units);
set_guide_bar_units(unit_mask);
_gcs[collector_index] = gc;
return gc;
RECT rect;
GetClientRect(_window, &rect);
rect.left = _right_margin;
InvalidateRect(_window, &rect, TRUE);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::clicked_label
// Access: Public, Virtual
// Description: Called when the user single-clicks on a label.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
clicked_label(int collector_index) {
if (collector_index >= 0) {
GtkStatsGraph::_monitor->open_strip_chart(GtkStatsGraph::_thread_index, collector_index, false);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::set_horizontal_scale
// Access: Public
// Description: Changes the amount of time the width of the
// horizontal axis represents. This may force a redraw.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
set_horizontal_scale(float time_width) {
PStatPianoRoll::set_horizontal_scale(time_width);
RECT rect;
GetClientRect(_window, &rect);
rect.bottom = _top_margin;
InvalidateRect(_window, &rect, TRUE);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::clear_region
// Access: Protected
// Description: Erases the chart area.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
clear_region() {
RECT rect = { 0, 0, get_xsize(), get_ysize() };
FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::begin_draw
// Access: Protected, Virtual
// Description: Erases the chart area in preparation for drawing it
// full of bars.
// Description: Erases the chart area in preparation for drawing a
// bunch of bars.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
begin_draw() {
_pixmap.draw_rectangle(_white_gc, true, 0, 0, get_xsize(), get_ysize());
Gdk_Font font = get_style()->gtkobj()->font;
int text_height = font.height();
clear_region();
// Draw in the guide bars.
int num_guide_bars = get_num_guide_bars();
for (int i = 0; i < num_guide_bars; i++) {
const GuideBar &bar = get_guide_bar(i);
int x = (int)((float)get_xsize() * bar._height / get_horizontal_scale());
if (x >= 5 && x <= get_xsize() - 5) {
// Only draw it if it's not too close to either edge.
switch (bar._style) {
case GBS_target:
_pixmap.draw_line(_light_gc, x, text_height + 4, x, get_ysize());
break;
case GBS_normal:
default:
_pixmap.draw_line(_dark_gc, x, text_height + 4, x, get_ysize());
break;
}
}
draw_guide_bar(_bitmap_dc, get_guide_bar(i));
}
}
////////////////////////////////////////////////////////////////////
@ -152,10 +182,17 @@ begin_draw() {
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
draw_bar(int row, int from_x, int to_x) {
if (row >= 0 && row < (int)_y_positions.size()) {
int y = height() - _y_positions[row];
_pixmap.draw_rectangle(get_collector_gc(get_label_collector(row)),
true, from_x, y - 6, to_x - from_x, 12);
if (row >= 0 && row < _label_stack.get_num_labels()) {
int y = _label_stack.get_label_y(row) - _graph_top;
int height = _label_stack.get_label_height(row);
RECT rect = {
from_x, y - height + 2,
to_x, y - 2,
};
int collector_index = get_label_collector(row);
HBRUSH brush = get_collector_brush(collector_index);
FillRect(_bitmap_dc, &rect, brush);
}
}
@ -167,31 +204,7 @@ draw_bar(int row, int from_x, int to_x) {
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
end_draw() {
// Draw in the labels for the guide bars. We do this in end_draw()
// instead of in begin_draw() so the labels will appear on top of
// any of the color bars.
Gdk_Font font = get_style()->gtkobj()->font;
int text_ascent = font.ascent();
int num_guide_bars = get_num_guide_bars();
for (int i = 0; i < num_guide_bars; i++) {
const GuideBar &bar = get_guide_bar(i);
int x = (int)((float)get_xsize() * bar._height / get_horizontal_scale());
if (x >= 5 && x <= get_xsize() - 5) {
// Only draw it if it's not too close to either edge.
int width = font.string_measure(bar._label);
_pixmap.draw_string(font, _black_gc, x - width / 2, text_ascent + 2,
bar._label);
}
}
GdkRectangle update_rect;
update_rect.x = 0;
update_rect.y = 0;
update_rect.width = get_xsize();
update_rect.height = get_ysize();
draw(&update_rect);
InvalidateRect(_graph_window, NULL, FALSE);
}
////////////////////////////////////////////////////////////////////
@ -202,126 +215,430 @@ end_draw() {
void GtkStatsPianoRoll::
idle() {
if (_labels_changed) {
pack_labels();
update_labels();
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::configure_event_impl
// Access: Private, Virtual
// Description: Creates a new backing pixmap of the appropriate size.
// Function: GtkStatsPianoRoll::window_proc
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
gint GtkStatsPianoRoll::
configure_event_impl(GdkEventConfigure *) {
if (width() != get_xsize() || height() != get_ysize() ||
_pixmap.gdkobj() == (GdkDrawable *)NULL) {
if (_pixmap) {
_pixmap.release();
LONG GtkStatsPianoRoll::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_LBUTTONDOWN:
if (_potential_drag_mode == DM_new_guide_bar) {
set_drag_mode(DM_new_guide_bar);
SetCapture(_graph_window);
return 0;
}
break;
default:
break;
}
return GtkStatsGraph::window_proc(hwnd, msg, wparam, lparam);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::graph_window_proc
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
LONG GtkStatsPianoRoll::
graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_LBUTTONDOWN:
if (_potential_drag_mode == DM_none) {
set_drag_mode(DM_scale);
PN_int16 x = LOWORD(lparam);
_drag_scale_start = pixel_to_height(x);
SetCapture(_graph_window);
return 0;
} else if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) {
set_drag_mode(DM_guide_bar);
PN_int16 x = LOWORD(lparam);
_drag_start_x = x;
SetCapture(_graph_window);
return 0;
}
break;
case WM_MOUSEMOVE:
if (_drag_mode == DM_none && _potential_drag_mode == DM_none) {
// When the mouse is over a color bar, highlight it.
PN_int16 x = LOWORD(lparam);
PN_int16 y = HIWORD(lparam);
_label_stack.highlight_label(get_collector_under_pixel(x, y));
// Now we want to get a WM_MOUSELEAVE when the mouse leaves the
// graph window.
TRACKMOUSEEVENT tme = {
sizeof(TRACKMOUSEEVENT),
TME_LEAVE,
_graph_window,
0
};
TrackMouseEvent(&tme);
} else {
// If the mouse is in some drag mode, stop highlighting.
_label_stack.highlight_label(-1);
}
_pixmap.create(get_window(), width(), height());
if (_drag_mode == DM_scale) {
PN_int16 x = LOWORD(lparam);
float ratio = (float)x / (float)get_xsize();
if (ratio > 0.0f) {
set_horizontal_scale(_drag_scale_start / ratio);
}
return 0;
Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
} else if (_drag_mode == DM_new_guide_bar) {
// We haven't created the new guide bar yet; we won't until the
// mouse comes within the graph's region.
PN_int16 x = LOWORD(lparam);
if (x >= 0 && x < get_xsize()) {
set_drag_mode(DM_guide_bar);
_drag_guide_bar = add_user_guide_bar(pixel_to_height(x));
return 0;
}
_white_gc = Gdk_GC(_pixmap);
setup_white_gc();
} else if (_drag_mode == DM_guide_bar) {
PN_int16 x = LOWORD(lparam);
move_user_guide_bar(_drag_guide_bar, pixel_to_height(x));
return 0;
}
break;
_black_gc = Gdk_GC(_pixmap);
_black_gc.set_foreground(system_colormap.black());
case WM_MOUSELEAVE:
// When the mouse leaves the graph, stop highlighting.
_label_stack.highlight_label(-1);
break;
_dark_gc = Gdk_GC(_pixmap);
Gdk_Color dark;
dark.set_grey_p(0.2);
system_colormap.alloc(dark);
_dark_gc.set_foreground(dark);
case WM_LBUTTONUP:
if (_drag_mode == DM_scale) {
set_drag_mode(DM_none);
ReleaseCapture();
return 0;
_light_gc = Gdk_GC(_pixmap);
Gdk_Color light;
light.set_grey_p(0.6);
system_colormap.alloc(light);
_light_gc.set_foreground(light);
} else if (_drag_mode == DM_guide_bar) {
PN_int16 x = LOWORD(lparam);
if (x < 0 || x >= get_xsize()) {
remove_user_guide_bar(_drag_guide_bar);
} else {
move_user_guide_bar(_drag_guide_bar, pixel_to_height(x));
}
set_drag_mode(DM_none);
ReleaseCapture();
return 0;
}
break;
_pixmap.draw_rectangle(_white_gc, true, 0, 0, width(), height());
case WM_LBUTTONDBLCLK:
{
// Double-clicking on a color bar in the graph is the same as
// double-clicking on the corresponding label.
PN_int16 x = LOWORD(lparam);
PN_int16 y = HIWORD(lparam);
clicked_label(get_collector_under_pixel(x, y));
return 0;
}
break;
changed_size(width(), height());
default:
break;
}
return true;
return GtkStatsGraph::graph_window_proc(hwnd, msg, wparam, lparam);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::expose_event_impl
// Access: Private, Virtual
// Description: Redraw the screen from the backing pixmap.
////////////////////////////////////////////////////////////////////
gint GtkStatsPianoRoll::
expose_event_impl(GdkEventExpose *event) {
get_window().draw_pixmap(_white_gc, _pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::pack_labels
// Access: Private
// Description:
// Function: GtkStatsPianoRoll::additional_window_paint
// Access: Protected, Virtual
// Description: This is called during the servicing of WM_PAINT; it
// gives a derived class opportunity to do some further
// painting into the window (the outer window, not the
// graph window).
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
pack_labels() {
// First, remove the old labels.
_label_align->remove();
additional_window_paint(HDC hdc) {
// Draw in the labels for the guide bars.
HFONT hfnt = (HFONT)GetStockObject(ANSI_VAR_FONT);
SelectObject(hdc, hfnt);
SetTextAlign(hdc, TA_LEFT | TA_BOTTOM);
SetBkMode(hdc, TRANSPARENT);
// Now add the new labels back in.
_label_box = manage(new Gtk::VBox);
_label_box->show();
_label_align->add(*_label_box);
int y = _top_margin;
Gdk_Font font = get_style()->gtkobj()->font;
int num_labels = get_num_labels();
while ((int)_y_positions.size() < num_labels) {
_y_positions.push_back(0);
int i;
int num_guide_bars = get_num_guide_bars();
for (i = 0; i < num_guide_bars; i++) {
draw_guide_label(hdc, y, get_guide_bar(i));
}
int y = 0;
for (int i = 0; i < num_labels; i++) {
int collector_index = get_label_collector(i);
GtkStatsLabel *label =
new GtkStatsLabel(get_monitor(), collector_index, font);
label->show();
int num_user_guide_bars = get_num_user_guide_bars();
for (i = 0; i < num_user_guide_bars; i++) {
draw_guide_label(hdc, y, get_user_guide_bar(i));
}
}
_label_box->pack_end(*manage(label), false, false);
_y_positions[i] = y + label->get_height() / 2;
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::additional_graph_window_paint
// Access: Protected, Virtual
// Description: This is called during the servicing of WM_PAINT; it
// gives a derived class opportunity to do some further
// painting into the window (the outer window, not the
// graph window).
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
additional_graph_window_paint(HDC hdc) {
int num_user_guide_bars = get_num_user_guide_bars();
for (int i = 0; i < num_user_guide_bars; i++) {
draw_guide_bar(hdc, get_user_guide_bar(i));
}
}
y += label->get_height();
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::consider_drag_start
// Access: Protected, Virtual
// Description: Based on the mouse position within the window's
// client area, look for draggable things the mouse
// might be hovering over and return the apprioprate
// DragMode enum or DM_none if nothing is indicated.
////////////////////////////////////////////////////////////////////
GtkStatsGraph::DragMode GtkStatsPianoRoll::
consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) {
if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) {
// See if the mouse is over a user-defined guide bar.
int x = mouse_x - _graph_left;
float from_height = pixel_to_height(x - 2);
float to_height = pixel_to_height(x + 2);
_drag_guide_bar = find_user_guide_bar(from_height, to_height);
if (_drag_guide_bar >= 0) {
return DM_guide_bar;
}
} else if (mouse_x < _left_margin - 2 ||
mouse_x > width - _right_margin + 2) {
// The mouse is left or right of the graph; maybe create a new
// guide bar.
return DM_new_guide_bar;
}
}
return GtkStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::get_collector_under_pixel
// Access: Private
// Description: Returns the collector index associated with the
// indicated vertical row, or -1.
////////////////////////////////////////////////////////////////////
int GtkStatsPianoRoll::
get_collector_under_pixel(int xpoint, int ypoint) {
if (_label_stack.get_num_labels() == 0) {
return -1;
}
// Assume all of the labels are the same height.
int height = _label_stack.get_label_height(0);
int row = (get_ysize() - ypoint) / height;
if (row >= 0 && row < _label_stack.get_num_labels()) {
return _label_stack.get_label_collector_index(row);
} else {
return -1;
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::update_labels
// Access: Private
// Description: Resets the list of labels.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
update_labels() {
_label_stack.clear_labels();
for (int i = 0; i < get_num_labels(); i++) {
int label_index =
_label_stack.add_label(GtkStatsGraph::_monitor, this,
GtkStatsGraph::_thread_index,
get_label_collector(i), true);
}
_labels_changed = false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::setup_white_gc
// Function: GtkStatsPianoRoll::draw_guide_bar
// Access: Private
// Description: Sets the color on _white_gc to be either actually
// white (if the chart is still alive) or a light gray
// (if the chart is dead).
// Description: Draws the line for the indicated guide bar on the
// graph.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
setup_white_gc() {
Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
draw_guide_bar(HDC hdc, const PStatGraph::GuideBar &bar) {
int x = height_to_pixel(bar._height);
if (_is_dead) {
Gdk_Color death;
death.set_grey_p(0.8);
system_colormap.alloc(death);
if (x > 0 && x < get_xsize() - 1) {
// Only draw it if it's not too close to either edge.
switch (bar._style) {
case GBS_target:
SelectObject(hdc, _light_pen);
break;
_white_gc.set_foreground(death);
} else {
_white_gc.set_foreground(system_colormap.white());
case GBS_user:
SelectObject(hdc, _user_guide_bar_pen);
break;
case GBS_normal:
SelectObject(hdc, _dark_pen);
break;
}
MoveToEx(hdc, x, 0, NULL);
LineTo(hdc, x, get_ysize());
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::draw_guide_label
// Access: Private
// Description: Draws the text for the indicated guide bar label at
// the top of the graph.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar) {
switch (bar._style) {
case GBS_target:
SetTextColor(hdc, _light_color);
break;
case GBS_user:
SetTextColor(hdc, _user_guide_bar_color);
break;
case GBS_normal:
SetTextColor(hdc, _dark_color);
break;
}
int x = height_to_pixel(bar._height);
const string &label = bar._label;
SIZE size;
GetTextExtentPoint32(hdc, label.data(), label.length(), &size);
if (bar._style != GBS_user) {
float from_height = pixel_to_height(x - size.cx);
float to_height = pixel_to_height(x + size.cx);
if (find_user_guide_bar(from_height, to_height) >= 0) {
// Omit the label: there's a user-defined guide bar in the same space.
return;
}
}
int this_x = _graph_left + x - size.cx / 2;
if (x >= 0 && x < get_xsize()) {
TextOut(hdc, this_x, y,
label.data(), label.length());
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::create_window
// Access: Private
// Description: Creates the window for this strip chart.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
create_window() {
if (_window) {
return;
}
HINSTANCE application = GetModuleHandle(NULL);
register_window_class(application);
const PStatClientData *client_data =
GtkStatsGraph::_monitor->get_client_data();
string thread_name = client_data->get_thread_name(GtkStatsGraph::_thread_index);
string window_title = thread_name + " thread piano roll";
RECT win_rect = {
0, 0,
_left_margin + get_xsize() + _right_margin,
_top_margin + get_ysize() + _bottom_margin
};
// compute window size based on desired client area size
AdjustWindowRect(&win_rect, graph_window_style, FALSE);
_window =
CreateWindow(_window_class_name, window_title.c_str(), graph_window_style,
CW_USEDEFAULT, CW_USEDEFAULT,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
GtkStatsGraph::_monitor->get_window(), NULL, application, 0);
if (!_window) {
nout << "Could not create PianoRoll window!\n";
exit(1);
}
SetWindowLongPtr(_window, 0, (LONG_PTR)this);
setup_label_stack();
// Ensure that the window is on top of the stack.
SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::register_window_class
// Access: Private, Static
// Description: Registers the window class for the pianoRoll window, if
// it has not already been registered.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoRoll::
register_window_class(HINSTANCE application) {
if (_window_class_registered) {
return;
}
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)static_window_proc;
wc.hInstance = application;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
wc.lpszMenuName = NULL;
wc.lpszClassName = _window_class_name;
// Reserve space to associate the this pointer with the window.
wc.cbWndExtra = sizeof(GtkStatsPianoRoll *);
if (!RegisterClass(&wc)) {
nout << "Could not register PianoRoll window class!\n";
exit(1);
}
_window_class_registered = true;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoRoll::static_window_proc
// Access: Private, Static
// Description:
////////////////////////////////////////////////////////////////////
LONG WINAPI GtkStatsPianoRoll::
static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
GtkStatsPianoRoll *self = (GtkStatsPianoRoll *)GetWindowLongPtr(hwnd, 0);
if (self != (GtkStatsPianoRoll *)NULL && self->_window == hwnd) {
return self->window_proc(hwnd, msg, wparam, lparam);
} else {
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsPianoRoll.h
// Created by: drose (18Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -21,72 +21,61 @@
#include "pandatoolbase.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsGraph.h"
#include "pStatPianoRoll.h"
#include "pointerTo.h"
#include <gtk--.h>
#include "pmap.h"
#include <windows.h>
class PStatView;
class GtkStatsGuide;
class GtkStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsPianoRoll
// Description : A special widget that draws a piano-roll style chart,
// Description : A window that draws a piano-roll style chart,
// which shows the collectors explicitly stopping and
// starting, one frame at a time.
////////////////////////////////////////////////////////////////////
class GtkStatsPianoRoll : public Gtk::DrawingArea, public PStatPianoRoll {
class GtkStatsPianoRoll : public PStatPianoRoll, public GtkStatsGraph {
public:
GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index,
int xsize, int ysize);
GtkStatsPianoRoll(GtkStatsMonitor *monitor, int thread_index);
virtual ~GtkStatsPianoRoll();
void mark_dead();
virtual void new_data(int thread_index, int frame_number);
virtual void force_redraw();
virtual void changed_graph_size(int graph_xsize, int graph_ysize);
Gtk::Alignment *get_labels();
virtual void set_time_units(int unit_mask);
virtual void clicked_label(int collector_index);
void set_horizontal_scale(float time_width);
Gdk_GC get_collector_gc(int collector_index);
private:
protected:
void clear_region();
virtual void begin_draw();
virtual void draw_bar(int row, int from_x, int to_x);
virtual void end_draw();
virtual void idle();
virtual gint configure_event_impl(GdkEventConfigure *event);
virtual gint expose_event_impl(GdkEventExpose *event);
void pack_labels();
void setup_white_gc();
LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
virtual LONG graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
virtual void additional_window_paint(HDC hdc);
virtual void additional_graph_window_paint(HDC hdc);
virtual DragMode consider_drag_start(int mouse_x, int mouse_y,
int width, int height);
private:
// Backing pixmap for drawing area.
Gdk_Pixmap _pixmap;
int get_collector_under_pixel(int xpoint, int ypoint);
void update_labels();
void draw_guide_bar(HDC hdc, const GuideBar &bar);
void draw_guide_label(HDC hdc, int y, const PStatGraph::GuideBar &bar);
// Graphics contexts for fg/bg. We don't use the contexts defined
// in the style, because that would probably interfere with the
// visibility of the chart.
Gdk_GC _white_gc;
Gdk_GC _black_gc;
Gdk_GC _dark_gc;
Gdk_GC _light_gc;
void create_window();
static void register_window_class(HINSTANCE application);
// Table of graphics contexts for our various collectors.
typedef pmap<int, Gdk_GC> GCs;
GCs _gcs;
static LONG GTKAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
// Table of Y-positions for each of our rows, measured from the
// bottom.
vector_int _y_positions;
Gtk::Alignment *_label_align;
Gtk::VBox *_label_box;
bool _is_dead;
static bool _window_class_registered;
static const char * const _window_class_name;
};
#include "gtkStatsPianoRoll.I"
#endif

View File

@ -1,164 +0,0 @@
// Filename: gtkStatsPianoWindow.cxx
// Created by: drose (18Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsPianoWindow.h"
#include "gtkStatsPianoRoll.h"
using Gtk::Menu_Helpers::MenuElem;
using Gtk::Menu_Helpers::SeparatorElem;
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsPianoWindow::
GtkStatsPianoWindow(GtkStatsMonitor *monitor, int thread_index,
int chart_xsize, int chart_ysize) :
GtkStatsWindow(monitor),
_thread_index(thread_index)
{
setup_menu();
layout_window(chart_xsize, chart_ysize);
show();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::mark_dead
// Access: Public, Virtual
// Description: Called when the client's connection has been lost,
// this should update the window in some obvious way to
// indicate that the window is no longer live.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoWindow::
mark_dead() {
GtkStatsWindow::mark_dead();
_chart->mark_dead();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::idle
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsPianoWindow::
idle() {
GtkStatsWindow::idle();
_chart->update();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::setup_menu
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsPianoWindow::
setup_menu() {
GtkStatsWindow::setup_menu();
Gtk::Menu *scale_menu = new Gtk::Menu;
scale_menu->items().push_back
(MenuElem("0.1 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 0.1f)));
scale_menu->items().push_back
(MenuElem("1 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 1.0f)));
scale_menu->items().push_back
(MenuElem("5 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 5.0f)));
scale_menu->items().push_back
(MenuElem("10 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 10.0f)));
scale_menu->items().push_back
(MenuElem("20 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 20.0f)));
scale_menu->items().push_back
(MenuElem("30 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 30.0f)));
scale_menu->items().push_back
(MenuElem("60 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 60.0f)));
scale_menu->items().push_back
(MenuElem("120 Hz",
bind(slot(this, &GtkStatsPianoWindow::menu_hscale), 120.0f)));
_menu->items().push_back(MenuElem("Scale", *manage(scale_menu)));
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::menu_new_window
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsPianoWindow::
menu_new_window() {
new GtkStatsPianoWindow(_monitor, _thread_index,
_chart->get_xsize(), _chart->get_ysize());
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::menu_hscale
// Access: Protected
// Description: Selects a new horizontal scale for the piano roll.
// This is done from the menu called "Scale".
//
// The units is in Hz.
////////////////////////////////////////////////////////////////////
void GtkStatsPianoWindow::
menu_hscale(float hz) {
_chart->set_horizontal_scale(1.0 / hz);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsPianoWindow::layout_window
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsPianoWindow::
layout_window(int chart_xsize, int chart_ysize) {
Gtk::HBox *hbox = new Gtk::HBox;
hbox = new Gtk::HBox;
hbox->show();
_main_box->pack_start(*manage(hbox), true, true, 8);
Gtk::Table *chart_table = new Gtk::Table(1, 2);
chart_table->show();
hbox->pack_start(*manage(chart_table), true, true, 8);
Gtk::Frame *frame = new Gtk::Frame;
frame->set_shadow_type(GTK_SHADOW_ETCHED_OUT);
frame->show();
chart_table->attach(*manage(frame), 1, 2, 0, 1);
_chart = new GtkStatsPianoRoll(_monitor, _thread_index,
chart_xsize, chart_ysize);
frame->add(*manage(_chart));
// We put the labels in a frame, too, so they'll line up vertically.
Gtk::Frame *label_frame = new Gtk::Frame;
label_frame->set_shadow_type(GTK_SHADOW_NONE);
label_frame->show();
label_frame->add(*manage(_chart->get_labels()));
chart_table->attach(*manage(label_frame), 0, 1, 0, 1,
0, (GTK_FILL|GTK_EXPAND), 4, 0);
_chart->show();
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsServer.cxx
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -19,7 +19,6 @@
#include "gtkStatsServer.h"
#include "gtkStatsMonitor.h"
////////////////////////////////////////////////////////////////////
// Function: GtkStatsServer::make_monitor
// Access: Public

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsServer.h
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -20,13 +20,12 @@
#define GTKSTATSSERVER_H
#include "pandatoolbase.h"
#include "pStatServer.h"
////////////////////////////////////////////////////////////////////
// Class : GtkStatsServer
// Description :
// Description : The class that owns the main loop, waiting for client
// connections.
////////////////////////////////////////////////////////////////////
class GtkStatsServer : public PStatServer {
public:
@ -34,3 +33,4 @@ public:
};
#endif

View File

@ -1,17 +0,0 @@
// Filename: gtkStatsStripChart.I
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsStripChart.cxx
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -17,16 +17,12 @@
////////////////////////////////////////////////////////////////////
#include "gtkStatsStripChart.h"
#include "gtkStatsLabel.h"
#include "gtkStatsGuide.h"
#include "request_initial_size.h"
#include "pStatThreadData.h"
#include "pStatFrameData.h"
#include "pStatView.h"
#include <algorithm>
#include "gtkStatsMonitor.h"
#include "pStatCollectorDef.h"
#include "numeric_types.h"
static const int default_strip_chart_width = 400;
static const int default_strip_chart_height = 100;
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::Constructor
@ -34,99 +30,234 @@
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsStripChart::
GtkStatsStripChart(GtkStatsMonitor *monitor, PStatView &view,
int collector_index, int xsize, int ysize) :
PStatStripChart(monitor, view, collector_index, xsize, ysize)
GtkStatsStripChart(GtkStatsMonitor *monitor, int thread_index,
int collector_index, bool show_level) :
PStatStripChart(monitor,
show_level ? monitor->get_level_view(collector_index, thread_index) : monitor->get_view(thread_index),
collector_index,
default_strip_chart_width,
default_strip_chart_height),
GtkStatsGraph(monitor, thread_index)
{
_is_dead = false;
set_events(GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
_brush_origin = 0;
_label_align = manage(new Gtk::Alignment(1.0, 1.0));
_label_align->show();
_left_margin = 96;
_right_margin = 32;
_top_margin = 16;
_bottom_margin = 8;
_label_box = NULL;
pack_labels();
if (show_level) {
// If it's a level-type graph, show the appropriate units.
if (_unit_name.empty()) {
set_guide_bar_units(GBU_named);
} else {
set_guide_bar_units(GBU_named | GBU_show_units);
}
_guide = manage(new GtkStatsGuide(this));
_guide->show();
} else {
// If it's a time-type graph, show the ms/Hz units.
set_guide_bar_units(get_guide_bar_units() | GBU_show_units);
}
request_initial_size(*this, get_xsize(), get_ysize());
_smooth_check_box = 0;
GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), _label_stack.setup(),
FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), _graph_window,
FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(_window), hbox);
gtk_widget_show_all(_window);
gtk_widget_show(_window);
clear_region();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::mark_dead
// Access: Public
// Description: Called when the client's connection has been lost,
// this should update the window in some obvious way to
// indicate that the window is no longer live.
// Function: GtkStatsStripChart::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsStripChart::
~GtkStatsStripChart() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::new_collector
// Access: Public, Virtual
// Description: Called whenever a new Collector definition is
// received from the client.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
mark_dead() {
_is_dead = true;
new_collector(int collector_index) {
GtkStatsGraph::new_collector(collector_index);
}
setup_white_gc();
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::new_data
// Access: Public, Virtual
// Description: Called as each frame's data is made available. There
// is no gurantee the frames will arrive in order, or
// that all of them will arrive at all. The monitor
// should be prepared to accept frames received
// out-of-order or missing.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
new_data(int thread_index, int frame_number) {
if (is_title_unknown()) {
string window_title = get_title_text();
if (!is_title_unknown()) {
gtk_window_set_title(GTK_WINDOW(_window), window_title.c_str());
}
}
if (!_pause) {
update();
/*
string text = format_number(get_average_net_value(), get_guide_bar_units(), get_guide_bar_unit_name());
if (_net_value_text != text) {
_net_value_text = text;
RECT rect;
GetClientRect(_window, &rect);
rect.bottom = _top_margin;
InvalidateRect(_window, &rect, TRUE);
}
*/
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::force_redraw
// Access: Public, Virtual
// Description: Called when it is necessary to redraw the entire graph.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
force_redraw() {
PStatStripChart::force_redraw();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::changed_graph_size
// Access: Public, Virtual
// Description: Called when the user has resized the window, forcing
// a resize of the graph.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
changed_graph_size(int graph_xsize, int graph_ysize) {
PStatStripChart::changed_size(graph_xsize, graph_ysize);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::set_time_units
// Access: Public, Virtual
// Description: Called when the user selects a new time units from
// the monitor pulldown menu, this should adjust the
// units for the graph to the indicated mask if it is a
// time-based graph.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
set_time_units(int unit_mask) {
int old_unit_mask = get_guide_bar_units();
if ((old_unit_mask & (GBU_hz | GBU_ms)) != 0) {
unit_mask = unit_mask & (GBU_hz | GBU_ms);
unit_mask |= (old_unit_mask & GBU_show_units);
set_guide_bar_units(unit_mask);
/*
RECT rect;
GetClientRect(_window, &rect);
rect.left = _right_margin;
InvalidateRect(_window, &rect, TRUE);
GetClientRect(_window, &rect);
rect.bottom = _top_margin;
InvalidateRect(_window, &rect, TRUE);
*/
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::set_scroll_speed
// Access: Public
// Description: Called when the user selects a new scroll speed from
// the monitor pulldown menu, this should adjust the
// speed for the graph to the indicated value.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
set_scroll_speed(float scroll_speed) {
// The speed factor indicates chart widths per minute.
if (scroll_speed != 0.0f) {
set_horizontal_scale(60.0f / scroll_speed);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::clicked_label
// Access: Public, Virtual
// Description: Called when the user single-clicks on a label.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
clicked_label(int collector_index) {
if (collector_index < 0) {
// Clicking on whitespace in the graph is the same as clicking on
// the top label.
collector_index = get_collector_index();
}
if (collector_index == get_collector_index() && collector_index != 0) {
// Clicking on the top label means to go up to the parent level.
const PStatClientData *client_data =
GtkStatsGraph::_monitor->get_client_data();
if (client_data->has_collector(collector_index)) {
const PStatCollectorDef &def =
client_data->get_collector_def(collector_index);
if (def._parent_index == 0 && get_view().get_show_level()) {
// Unless the parent is "Frame", and we're not a time collector.
} else {
set_collector_index(def._parent_index);
}
}
if (!first_data()) {
force_redraw();
} else {
clear_region();
// Clicking on any other label means to focus on that.
set_collector_index(collector_index);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::get_labels
// Function: GtkStatsStripChart::set_vertical_scale
// Access: Public
// Description: Returns an alignment widget that contains all of the
// labels appropriate to this chart, already formatted
// and stacked up bottom-to-top. The window should pack
// this widget suitably near the strip chart.
// Description: Changes the value the height of the vertical axis
// represents. This may force a redraw.
////////////////////////////////////////////////////////////////////
Gtk::Alignment *GtkStatsStripChart::
get_labels() {
return _label_align;
void GtkStatsStripChart::
set_vertical_scale(float value_height) {
PStatStripChart::set_vertical_scale(value_height);
GdkRectangle rect = {
0, 0, get_xsize(), get_ysize()
};
gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::get_guide
// Access: Public
// Description: Returns a widget that contains the numeric labels for
// the guide bars. The window should pack this widget
// suitably near the strip chart.
// Function: GtkStatsStripChart::update_labels
// Access: Protected, Virtual
// Description: Resets the list of labels.
////////////////////////////////////////////////////////////////////
GtkStatsGuide *GtkStatsStripChart::
get_guide() {
return _guide;
}
void GtkStatsStripChart::
update_labels() {
PStatStripChart::update_labels();
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::get_collector_gc
// Access: Public
// Description: Returns a graphics context suitable for drawing in
// the indicated collector's color.
////////////////////////////////////////////////////////////////////
Gdk_GC GtkStatsStripChart::
get_collector_gc(int collector_index) {
GCs::iterator gi;
gi = _gcs.find(collector_index);
if (gi != _gcs.end()) {
return (*gi).second;
_label_stack.clear_labels();
for (int i = 0; i < get_num_labels(); i++) {
_label_stack.add_label(GtkStatsGraph::_monitor, this, _thread_index,
get_label_collector(i), false);
}
// Ask the monitor what color this guy should be.
RGBColorf rgb = get_monitor()->get_collector_color(collector_index);
Gdk_Color color;
color.set_rgb_p(rgb[0], rgb[1], rgb[2]);
// Now allocate the color from the system colormap.
Gdk_Colormap::get_system().alloc(color);
// Allocate a new graphics context.
Gdk_GC gc(_pixmap);
gc.set_foreground(color);
_gcs[collector_index] = gc;
return gc;
_labels_changed = false;
}
////////////////////////////////////////////////////////////////////
@ -136,8 +267,9 @@ get_collector_gc(int collector_index) {
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
clear_region() {
_pixmap.draw_rectangle(_white_gc, true, 0, 0, get_xsize(), get_ysize());
end_draw(0, get_xsize());
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, 0, 0,
get_xsize(), get_ysize());
}
////////////////////////////////////////////////////////////////////
@ -149,28 +281,19 @@ clear_region() {
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
copy_region(int start_x, int end_x, int dest_x) {
_pixmap.copy_area(_white_gc, 0, 0,
_pixmap, start_x, 0,
end_x - start_x + 1, get_ysize());
gdk_draw_drawable(_pixmap, _pixmap_gc, _pixmap,
start_x, 0, dest_x, 0,
end_x - start_x, get_ysize());
// Also shift the brush origin over, so we still get proper
// dithering.
_brush_origin += (dest_x - start_x);
// SetBrushOrgEx(_bitmap_dc, _brush_origin, 0, NULL);
// We could make a window-to-window copy to implement scrolling in
// the window. But this leads to trouble if the scrolling window
// isn't on top. Instead, we'll just do the scroll in the pixmap,
// and then blt the pixmap back out--in principle, this ought to be
// just as fast.
/*
Gdk_Window window = get_window();
window.copy_area(_white_gc, 0, 0,
window, start_x, 0,
end_x - start_x + 1, get_ysize());
*/
GdkRectangle update_rect;
update_rect.x = dest_x;
update_rect.y = 0;
update_rect.width = end_x - start_x + 1;
update_rect.height = get_ysize();
draw(&update_rect);
GdkRectangle rect = {
dest_x, 0, end_x - start_x, get_ysize()
};
gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
}
////////////////////////////////////////////////////////////////////
@ -182,32 +305,32 @@ copy_region(int start_x, int end_x, int dest_x) {
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
while (w > 0) {
// Start by clearing the band first.
_pixmap.draw_line(_white_gc, x, 0, x, get_ysize());
// Start by clearing the band first.
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, x, 0,
w + 1, get_ysize());
float overall_time = 0.0;
int y = get_ysize();
float overall_time = 0.0;
int y = get_ysize();
FrameData::const_iterator fi;
for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
const ColorData &cd = (*fi);
overall_time += cd._net_value;
FrameData::const_iterator fi;
for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
const ColorData &cd = (*fi);
overall_time += cd._net_value;
GdkGC *gc = get_collector_gc(cd._collector_index);
if (overall_time > get_vertical_scale()) {
// Off the top. Go ahead and clamp it by hand, in case it's so
// far off the top we'd overflow the 16-bit pixel value.
_pixmap.draw_line(get_collector_gc(cd._collector_index), x, y, x, 0);
// And we can consider ourselves done now.
break;
}
if (overall_time > get_vertical_scale()) {
// Off the top. Go ahead and clamp it by hand, in case it's so
// far off the top we'd overflow the 16-bit pixel value.
gdk_draw_rectangle(_pixmap, gc, TRUE, x, 0, w + 1, y);
int top_y = height_to_pixel(overall_time);
_pixmap.draw_line(get_collector_gc(cd._collector_index), x, y, x, top_y);
y = top_y;
// And we can consider ourselves done now.
return;
}
x++;
w--;
int top_y = height_to_pixel(overall_time);
gdk_draw_rectangle(_pixmap, gc, TRUE, x, top_y, w + 1, y);
y = top_y;
}
}
@ -218,11 +341,9 @@ draw_slice(int x, int w, const PStatStripChart::FrameData &fdata) {
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
draw_empty(int x, int w) {
while (w > 0) {
_pixmap.draw_line(_white_gc, x, 0, x, get_ysize());
x++;
w--;
}
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_white);
gdk_draw_rectangle(_pixmap, _pixmap_gc, TRUE, x, 0,
w + 1, get_ysize());
}
////////////////////////////////////////////////////////////////////
@ -232,7 +353,8 @@ draw_empty(int x, int w) {
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
draw_cursor(int x) {
_pixmap.draw_line(_black_gc, x, 0, x, get_ysize());
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_black);
gdk_draw_line(_pixmap, _pixmap_gc, x, 0, x, get_ysize());
}
////////////////////////////////////////////////////////////////////
@ -248,181 +370,103 @@ end_draw(int from_x, int to_x) {
// Draw in the guide bars.
int num_guide_bars = get_num_guide_bars();
for (int i = 0; i < num_guide_bars; i++) {
const GuideBar &bar = get_guide_bar(i);
int y = height_to_pixel(bar._height);
if (y >= 5) {
// Only draw it if it's not too close to the top.
switch (bar._style) {
case GBS_target:
_pixmap.draw_line(_light_gc, from_x, y, to_x, y);
break;
case GBS_normal:
default:
_pixmap.draw_line(_dark_gc, from_x, y, to_x, y);
break;
}
}
draw_guide_bar(from_x, to_x, get_guide_bar(i));
}
GdkRectangle update_rect;
update_rect.x = from_x;
update_rect.y = 0;
update_rect.width = to_x - from_x + 1;
update_rect.height = get_ysize();
draw(&update_rect);
GdkRectangle rect = {
from_x, 0, to_x - from_x + 1, get_ysize()
};
gdk_window_invalidate_rect(_graph_window->window, &rect, FALSE);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::idle
// Function: GtkStatsStripChart::consider_drag_start
// Access: Protected, Virtual
// Description: Called at the end of the draw cycle.
// Description: Based on the mouse position within the window's
// client area, look for draggable things the mouse
// might be hovering over and return the apprioprate
// DragMode enum or DM_none if nothing is indicated.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
idle() {
if (_labels_changed) {
pack_labels();
}
if (_guide_bars_changed) {
GdkRectangle update_rect;
update_rect.x = 0;
update_rect.y = 0;
update_rect.width = _guide->width();
update_rect.height = _guide->height();
_guide->draw(&update_rect);
_guide_bars_changed = false;
}
}
GtkStatsGraph::DragMode GtkStatsStripChart::
consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
if (mouse_x >= _graph_left && mouse_x < _graph_left + get_xsize()) {
if (mouse_y >= _graph_top && mouse_y < _graph_top + get_ysize()) {
// See if the mouse is over a user-defined guide bar.
int y = mouse_y - _graph_top;
float from_height = pixel_to_height(y + 2);
float to_height = pixel_to_height(y - 2);
_drag_guide_bar = find_user_guide_bar(from_height, to_height);
if (_drag_guide_bar >= 0) {
return DM_guide_bar;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::configure_event_impl
// Access: Private, Virtual
// Description: Creates a new backing pixmap of the appropriate size.
////////////////////////////////////////////////////////////////////
gint GtkStatsStripChart::
configure_event_impl(GdkEventConfigure *) {
if (width() != get_xsize() || height() != get_ysize() ||
_pixmap.gdkobj() == (GdkDrawable *)NULL) {
bool is_initial = true;
if (_pixmap) {
is_initial = false;
_pixmap.release();
} else {
// The mouse is above or below the graph; maybe create a new
// guide bar.
return DM_new_guide_bar;
}
_pixmap.create(get_window(), width(), height());
Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
_white_gc = Gdk_GC(_pixmap);
setup_white_gc();
_black_gc = Gdk_GC(_pixmap);
_black_gc.set_foreground(system_colormap.black());
_dark_gc = Gdk_GC(_pixmap);
Gdk_Color dark;
dark.set_grey_p(0.2);
system_colormap.alloc(dark);
_dark_gc.set_foreground(dark);
_light_gc = Gdk_GC(_pixmap);
Gdk_Color light;
light.set_grey_p(0.6);
system_colormap.alloc(light);
_light_gc.set_foreground(light);
_pixmap.draw_rectangle(_white_gc, true, 0, 0, width(), height());
changed_size(width(), height());
}
return true;
return GtkStatsGraph::consider_drag_start(mouse_x, mouse_y, width, height);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::expose_event_impl
// Access: Private, Virtual
// Description: Redraw the screen from the backing pixmap.
////////////////////////////////////////////////////////////////////
gint GtkStatsStripChart::
expose_event_impl(GdkEventExpose *event) {
get_window().draw_pixmap(_white_gc, _pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::button_press_event_impl
// Access: Private, Virtual
// Description:
////////////////////////////////////////////////////////////////////
gint GtkStatsStripChart::
button_press_event_impl(GdkEventButton *button) {
if (button->type == GDK_2BUTTON_PRESS && button->button == 1) {
int collector_index = get_collector_under_pixel((int)button->x, (int)button->y);
collector_picked(collector_index);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::pack_labels
// Access: Private
// Description:
// Function: GtkStatsStripChart::set_drag_mode
// Access: Protected, Virtual
// Description: This should be called whenever the drag mode needs to
// change state. It provides hooks for a derived class
// to do something special.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
pack_labels() {
// First, remove the old labels.
_label_align->remove();
set_drag_mode(GtkStatsGraph::DragMode drag_mode) {
GtkStatsGraph::set_drag_mode(drag_mode);
// Now add the new labels back in.
_label_box = manage(new Gtk::VBox);
_label_box->show();
_label_align->add(*_label_box);
switch (_drag_mode) {
case DM_scale:
case DM_left_margin:
case DM_right_margin:
case DM_sizing:
// Disable smoothing for these expensive operations.
set_average_mode(false);
break;
Gdk_Font font = get_style()->gtkobj()->font;
int num_labels = get_num_labels();
for (int i = 0; i < num_labels; i++) {
int collector_index = get_label_collector(i);
GtkStatsLabel *label =
new GtkStatsLabel(get_monitor(), collector_index, font);
label->show();
label->collector_picked.connect(collector_picked.slot());
_label_box->pack_end(*manage(label), false, false);
default:
// Restore smoothing according to the current setting of the check
// box.
/*
int result = SendMessage(_smooth_check_box, BM_GETCHECK, 0, 0);
set_average_mode(result == BST_CHECKED);
*/
break;
}
_labels_changed = false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripChart::setup_white_gc
// Function: GtkStatsStripChart::draw_guide_bar
// Access: Private
// Description: Sets the color on _white_gc to be either actually
// white (if the chart is still alive) or a light gray
// (if the chart is dead).
// Description: Draws the line for the indicated guide bar on the
// graph.
////////////////////////////////////////////////////////////////////
void GtkStatsStripChart::
setup_white_gc() {
Gdk_Colormap system_colormap = Gdk_Colormap::get_system();
draw_guide_bar(int from_x, int to_x,
const PStatGraph::GuideBar &bar) {
int y = height_to_pixel(bar._height);
if (_is_dead) {
Gdk_Color death;
death.set_grey_p(0.8);
system_colormap.alloc(death);
if (y > 0) {
// Only draw it if it's not too close to the top.
switch (bar._style) {
case GBS_target:
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_light_gray);
break;
_white_gc.set_foreground(death);
} else {
_white_gc.set_foreground(system_colormap.white());
case GBS_user:
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_user_guide_bar);
break;
case GBS_normal:
gdk_gc_set_rgb_fg_color(_pixmap_gc, &rgb_dark_gray);
break;
}
gdk_draw_line(_pixmap, _pixmap_gc, from_x, y, to_x, y);
}
}

View File

@ -1,5 +1,5 @@
// Filename: gtkStatsStripChart.h
// Created by: drose (14Jul00)
// Created by: drose (16Jan06)
//
////////////////////////////////////////////////////////////////////
//
@ -21,40 +21,37 @@
#include "pandatoolbase.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsGraph.h"
#include "pStatStripChart.h"
#include "pointerTo.h"
#include <gtk--.h>
#include "pmap.h"
#include <gtk/gtk.h>
class PStatView;
class GtkStatsGuide;
class GtkStatsMonitor;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsStripChart
// Description : A special widget that draws a strip chart, given a
// view.
// Description : A window that draws a strip chart, given a view.
////////////////////////////////////////////////////////////////////
class GtkStatsStripChart : public Gtk::DrawingArea, public PStatStripChart {
class GtkStatsStripChart : public PStatStripChart, public GtkStatsGraph {
public:
GtkStatsStripChart(GtkStatsMonitor *monitor,
PStatView &view, int collector_index,
int xsize, int ysize);
int thread_index, int collector_index, bool show_level);
virtual ~GtkStatsStripChart();
void mark_dead();
virtual void new_collector(int collector_index);
virtual void new_data(int thread_index, int frame_number);
virtual void force_redraw();
virtual void changed_graph_size(int graph_xsize, int graph_ysize);
Gtk::Alignment *get_labels();
GtkStatsGuide *get_guide();
virtual void set_time_units(int unit_mask);
virtual void set_scroll_speed(float scroll_speed);
virtual void clicked_label(int collector_index);
void set_vertical_scale(float value_height);
Gdk_GC get_collector_gc(int collector_index);
protected:
virtual void update_labels();
// This signal is thrown when the user float-clicks on a label or
// on a band of color.
SigC::Signal1<void, int> collector_picked;
private:
virtual void clear_region();
virtual void copy_region(int start_x, int end_x, int dest_x);
virtual void draw_slice(int x, int w,
@ -62,38 +59,25 @@ private:
virtual void draw_empty(int x, int w);
virtual void draw_cursor(int x);
virtual void end_draw(int from_x, int to_x);
virtual void idle();
virtual gint configure_event_impl(GdkEventConfigure *event);
virtual gint expose_event_impl(GdkEventExpose *event);
virtual gint button_press_event_impl(GdkEventButton *button);
void pack_labels();
void setup_white_gc();
virtual DragMode consider_drag_start(int mouse_x, int mouse_y,
int width, int height);
virtual void set_drag_mode(DragMode drag_mode);
private:
// Backing pixmap for drawing area.
Gdk_Pixmap _pixmap;
void draw_guide_bar(int from_x, int to_x,
const PStatGraph::GuideBar &bar);
// Graphics contexts for fg/bg. We don't use the contexts defined
// in the style, because that would probably interfere with the
// visibility of the strip chart.
Gdk_GC _white_gc;
Gdk_GC _black_gc;
Gdk_GC _dark_gc;
Gdk_GC _light_gc;
private:
// Table of graphics contexts for our various collectors.
typedef pmap<int, Gdk_GC> GCs;
GCs _gcs;
int _brush_origin;
string _net_value_text;
Gtk::Alignment *_label_align;
Gtk::VBox *_label_box;
GtkStatsGuide *_guide;
bool _is_dead;
GtkWidget *_smooth_check_box;
static bool _window_class_registered;
static const char * const _window_class_name;
};
#include "gtkStatsStripChart.I"
#endif

View File

@ -1,459 +0,0 @@
// Filename: gtkStatsStripWindow.cxx
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsStripWindow.h"
#include "gtkStatsStripChart.h"
#include "gtkStatsGuide.h"
#include "pStatCollectorDef.h"
#include "string_utils.h"
#include <stdio.h> // for sprintf
using Gtk::Menu_Helpers::MenuElem;
using Gtk::Menu_Helpers::CheckMenuElem;
using Gtk::Menu_Helpers::SeparatorElem;
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsStripWindow::
GtkStatsStripWindow(GtkStatsMonitor *monitor, int thread_index,
int collector_index, bool show_level,
int chart_xsize, int chart_ysize) :
GtkStatsWindow(monitor),
_thread_index(thread_index),
_collector_index(collector_index),
_show_level(show_level)
{
_title_unknown = false;
_setup_scale_menu = false;
_smooth = false;
setup_menu();
layout_window(chart_xsize, chart_ysize);
new_collector(); // To set up the menus in case we can.
show();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::mark_dead
// Access: Public, Virtual
// Description: Called when the client's connection has been lost,
// this should update the window in some obvious way to
// indicate that the window is no longer live.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
mark_dead() {
GtkStatsWindow::mark_dead();
_chart->mark_dead();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::new_collector
// Access: Public, Virtual
// Description: Called when a new collector has become known.
//
// For the GtkStatsStripWindow, this forces a rebuild of
// the menu that selects the collectors available for
// picking levels.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
new_collector() {
const PStatClientData *client_data = _monitor->get_client_data();
// Determine the set of collectors that display level data. We'll
// want to put these on the "Levels" pull-down menu.
pset<int> levels;
int num_collectors = client_data->get_num_collectors();
for (int i = 0; i < num_collectors; i++) {
if (client_data->has_collector(i) &&
client_data->get_collector_has_level(i)) {
// We only put top-level entries on the menu. Thus, walk up
// from this collector to its top level (the one below Frame).
int collector_index = i;
const PStatCollectorDef &def =
client_data->get_collector_def(collector_index);
int parent_index = def._parent_index;
while (parent_index != 0) {
collector_index = parent_index;
const PStatCollectorDef &def =
client_data->get_collector_def(collector_index);
parent_index = def._parent_index;
}
levels.insert(collector_index);
}
}
// Now put the collectors we found on the menu.
_levels_menu->items().clear();
pset<int>::const_iterator li;
for (li = levels.begin(); li != levels.end(); ++li) {
int collector_index = (*li);
_levels_menu->items().push_back
(MenuElem(client_data->get_collector_name(collector_index),
bind(slot(this, &GtkStatsStripWindow::menu_show_levels), collector_index)));
}
// Also re-set-up the scale menu, in case the properties have changed.
setup_scale_menu();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::idle
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
idle() {
GtkStatsWindow::idle();
_chart->update();
const PStatThreadData *thread_data = _chart->get_view().get_thread_data();
if (!thread_data->is_empty()) {
float frame_rate = thread_data->get_frame_rate();
char buffer[128];
sprintf(buffer, "Frame rate: %0.1f Hz", frame_rate);
_frame_rate_label->set_text(buffer);
}
if (_title_unknown) {
_title_label->set_text(get_title_text());
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::setup_menu
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
setup_menu() {
GtkStatsWindow::setup_menu();
Gtk::Menu *speed_menu = new Gtk::Menu;
speed_menu->items().push_back
(MenuElem("1", // 1 chart width scrolls by per minute.
bind(slot(this, &GtkStatsStripWindow::menu_hscale), 1.0f)));
speed_menu->items().push_back
(MenuElem("2", // 2 chart widths scroll by per minute.
bind(slot(this, &GtkStatsStripWindow::menu_hscale), 2.0f)));
speed_menu->items().push_back
(MenuElem("3",
bind(slot(this, &GtkStatsStripWindow::menu_hscale), 3.0f)));
speed_menu->items().push_back
(MenuElem("6",
bind(slot(this, &GtkStatsStripWindow::menu_hscale), 6.0f)));
speed_menu->items().push_back
(MenuElem("12",
bind(slot(this, &GtkStatsStripWindow::menu_hscale), 12.0f)));
_menu->items().push_back(MenuElem("Speed", *manage(speed_menu)));
_scale_menu = new Gtk::Menu;
_scale_menu->items().push_back
(CheckMenuElem("Smooth",
slot(this, &GtkStatsStripWindow::menu_smooth)));
_scale_menu->items().push_back(SeparatorElem());
_scale_menu->items().push_back
(MenuElem("Auto scale",
slot(this, &GtkStatsStripWindow::menu_auto_vscale)));
_menu->items().push_back(MenuElem("Scale", *manage(_scale_menu)));
_levels_menu = new Gtk::Menu;
_menu->items().push_back(MenuElem("Levels", *manage(_levels_menu)));
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::setup_scale_menu
// Access: Protected
// Description: Sets up the options on the scale menu. We can't do
// this until we have initialized the _chart member and
// we have gotten our first collector_index.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
setup_scale_menu() {
if (_setup_scale_menu) {
// Already done it.
return;
}
const PStatClientData *client_data = _monitor->get_client_data();
if (!client_data->has_collector(_collector_index)) {
// Can't set up the scale menu yet.
return;
}
const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
float base_scale = 1.0;
string unit_name = def._level_units;
if (_show_level) {
_chart->set_guide_bar_unit_name(unit_name);
_chart->set_guide_bar_units(PStatGraph::GBU_named);
} else {
_chart->set_guide_bar_units(PStatGraph::GBU_ms);
}
if (def._suggested_scale != 0.0) {
base_scale = def._suggested_scale;
} else if (!_show_level) {
base_scale = 1.0 / _chart->get_target_frame_rate();
}
static const float scales[] = {
50.0,
10.0,
5.0,
2.0,
1.0,
0.5,
0.2,
0.1,
0.02,
};
static const int num_scales = sizeof(scales) / sizeof(float);
for (int i = 0; i < num_scales; i++) {
float scale = base_scale * scales[i];
string label;
if (_show_level) {
label = _chart->format_number(scale, PStatGraph::GBU_named | PStatGraph::GBU_show_units, unit_name);
} else {
label = _chart->format_number(scale, PStatGraph::GBU_ms | PStatGraph::GBU_hz | PStatGraph::GBU_show_units);
}
_scale_menu->items().push_back
(MenuElem(label,
bind(slot(this, &GtkStatsStripWindow::menu_vscale), scale)));
}
_setup_scale_menu = true;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::menu_new_window
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
menu_new_window() {
new GtkStatsStripWindow(_monitor, _thread_index, _collector_index,
_show_level,
_chart->get_xsize(), _chart->get_ysize());
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::menu_hscale
// Access: Protected
// Description: Selects a new horizontal scale for the strip chart.
// This is done from the menu called "Speed", since
// changing the horizontal scale most obviously affects
// the scrolling speed.
//
// The units is in chart width per minute.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
menu_hscale(float wpm) {
_chart->set_horizontal_scale(60.0 / wpm);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::menu_vscale
// Access: Protected
// Description: Selects a new vertical scale for the strip chart.
// This is done from the menu called "Scale".
//
// The units is in seconds, or whatever the units
// of choice are.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
menu_vscale(float max_height) {
_chart->set_vertical_scale(max_height);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::menu_smooth
// Access: Protected
// Description: Toggles the "smooth" state of the check menu.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
menu_smooth() {
_smooth = !_smooth;
_chart->set_average_mode(_smooth);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::menu_auto_vscale
// Access: Protected
// Description: Selects a suitable vertical scale based on the data
// already visible in the chart.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
menu_auto_vscale() {
_chart->set_auto_vertical_scale();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::menu_show_levels
// Access: Protected
// Description: Shows the level values known for the indicated
// collector.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
menu_show_levels(int collector_index) {
new GtkStatsStripWindow(_monitor, _thread_index, collector_index,
true,
_chart->get_xsize(), _chart->get_ysize());
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::open_subchart
// Access: Protected
// Description: This is called in response to the collector_picked
// signal from the strip chart, which is generated when
// the user double-clicks on a band of color or a label.
//
// This opens up a new window focusing just on the
// indicated collector.
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
open_subchart(int collector_index) {
new GtkStatsStripWindow(_monitor, _thread_index, collector_index,
_show_level,
_chart->get_xsize(), _chart->get_ysize());
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::layout_window
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsStripWindow::
layout_window(int chart_xsize, int chart_ysize) {
Gtk::HBox *hbox = new Gtk::HBox;
hbox = new Gtk::HBox;
hbox->show();
_main_box->pack_start(*manage(hbox), true, true, 8);
Gtk::Table *chart_table = new Gtk::Table(3, 2);
chart_table->show();
hbox->pack_start(*manage(chart_table), true, true, 8);
Gtk::HBox *title_hbox = new Gtk::HBox;
title_hbox->show();
chart_table->attach(*manage(title_hbox), 1, 2, 0, 1,
(GTK_FILL|GTK_EXPAND), 0);
_title_label = new Gtk::Label(get_title_text());
if (_collector_index != 0 || _thread_index != 0) {
_title_label->show();
_title_label->set_alignment(0.0, 0.5);
title_hbox->pack_start(*manage(_title_label), true, true);
}
_frame_rate_label = new Gtk::Label;
if (_collector_index == 0) {
_frame_rate_label->show();
_frame_rate_label->set_alignment(1.0, 0.5);
title_hbox->pack_start(*manage(_frame_rate_label), true, true);
}
Gtk::Frame *frame = new Gtk::Frame;
frame->set_shadow_type(GTK_SHADOW_ETCHED_OUT);
frame->show();
chart_table->attach(*manage(frame), 1, 2, 1, 2);
if (_show_level) {
_chart = new GtkStatsStripChart(_monitor,
_monitor->get_level_view(_collector_index, _thread_index),
_collector_index,
chart_xsize, chart_ysize);
} else {
_chart = new GtkStatsStripChart(_monitor,
_monitor->get_view(_thread_index),
_collector_index,
chart_xsize, chart_ysize);
}
_chart->collector_picked.
connect(slot(this, &GtkStatsStripWindow::open_subchart));
frame->add(*manage(_chart));
chart_table->attach(*_chart->get_labels(), 0, 1, 1, 2,
0, (GTK_FILL|GTK_EXPAND), 4, 0);
chart_table->attach(*_chart->get_guide(), 2, 3, 1, 2,
0, (GTK_FILL|GTK_EXPAND), 4, 0);
_chart->show();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsStripWindow::get_title_text
// Access: Private
// Description: Returns the text suitable for the title label on the
// top line.
////////////////////////////////////////////////////////////////////
string GtkStatsStripWindow::
get_title_text() {
string text;
_title_unknown = false;
const PStatClientData *client_data = _monitor->get_client_data();
if (client_data->has_collector(_collector_index)) {
const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
if (_show_level) {
if (def._level_units.empty()) {
text = def._name;
} else {
text = def._name + " (" + def._level_units + ")";
}
} else {
text = def._name + " time";
}
} else {
_title_unknown = true;
}
if (_thread_index != 0) {
if (client_data->has_thread(_thread_index)) {
text += "(" + client_data->get_thread_name(_thread_index) + " thread)";
} else {
_title_unknown = true;
}
}
return text;
}

View File

@ -1,78 +0,0 @@
// Filename: gtkStatsStripWindow.h
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSSTRIPWINDOW_H
#define GTKSTATSSTRIPWINDOW_H
#include "pandatoolbase.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsWindow.h"
class GtkStatsStripChart;
////////////////////////////////////////////////////////////////////
// Class : GtkStatsStripWindow
// Description : A window that contains your basic one-thread,
// one-level strip chart.
////////////////////////////////////////////////////////////////////
class GtkStatsStripWindow : public GtkStatsWindow {
public:
GtkStatsStripWindow(GtkStatsMonitor *monitor, int thread_index,
int collector_index, bool show_level,
int chart_xsize, int chart_ysize);
virtual void mark_dead();
virtual void new_collector();
virtual void idle();
protected:
virtual void setup_menu();
void setup_scale_menu();
virtual void menu_new_window();
void menu_hscale(float wpm);
void menu_vscale(float max_height);
void menu_smooth();
void menu_auto_vscale();
void menu_show_levels(int collector_index);
void open_subchart(int collector_index);
private:
void layout_window(int chart_xsize, int chart_ysize);
string get_title_text();
private:
int _thread_index;
int _collector_index;
bool _show_level;
bool _title_unknown;
bool _setup_scale_menu;
Gtk::Label *_title_label;
Gtk::Label *_frame_rate_label;
GtkStatsStripChart *_chart;
Gtk::Menu *_scale_menu;
Gtk::Menu *_levels_menu;
bool _smooth;
};
#endif

View File

@ -1,210 +0,0 @@
// Filename: gtkStatsWindow.cxx
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkStatsWindow.h"
#include "gtkStatsMonitor.h"
#include "gtkStatsStripWindow.h"
#include "gtkStatsPianoWindow.h"
using Gtk::Menu_Helpers::MenuElem;
using Gtk::Menu_Helpers::SeparatorElem;
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkStatsWindow::
GtkStatsWindow(GtkStatsMonitor *monitor) : _monitor(monitor) {
_monitor->add_window(this);
update_title();
setup();
_main_box = new Gtk::VBox;
_main_box->show();
add(*manage(_main_box));
_menu = manage(new Gtk::MenuBar);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::destruct
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool GtkStatsWindow::
destruct() {
if (BasicGtkWindow::destruct()) {
_monitor->remove_window(this);
_monitor.clear();
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::update_title
// Access: Public, Virtual
// Description: Sets the title bar appropriately, once the client's
// information is known.
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
update_title() {
if (_monitor->is_client_known()) {
string title =
_monitor->get_client_progname() + " from " + _monitor->get_client_hostname();
if (!_monitor->is_alive()) {
title += " (closed)";
}
set_title(title);
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::mark_dead
// Access: Public, Virtual
// Description: Called when the client's connection has been lost,
// this should update the window in some obvious way to
// indicate that the window is no longer live.
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
mark_dead() {
update_title();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::new_collector
// Access: Public, Virtual
// Description: Called when a new collector has become known, in case
// the window cares.
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
new_collector() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::idle
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
idle() {
if (_monitor->_new_collector) {
new_collector();
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::setup_menu
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
setup_menu() {
_file_menu = new Gtk::Menu;
_file_menu->items().push_back
(MenuElem("New strip chart",
slot(this, &GtkStatsWindow::menu_open_strip_chart)));
_file_menu->items().push_back
(MenuElem("New piano roll",
slot(this, &GtkStatsWindow::menu_open_piano_roll)));
/*
_file_menu->items().push_back
(MenuElem("New window",
slot(this, &GtkStatsWindow::menu_new_window)));
*/
_file_menu->items().push_back(SeparatorElem());
_file_menu->items().push_back
(MenuElem("Disconnect from client",
slot(this, &GtkStatsWindow::menu_disconnect)));
_file_menu->items().push_back
(MenuElem("Close window",
slot(this, &GtkStatsWindow::menu_close_window)));
_file_menu->items().push_back
(MenuElem("Close all windows this client",
slot(this, &GtkStatsWindow::menu_close_all_windows)));
_menu->items().push_back(MenuElem("File", *manage(_file_menu)));
_menu->show();
_main_box->pack_start(*_menu, false, false);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::menu_open_strip_chart
// Access: Protected
// Description: Open up a new strip-chart style window for the main
// thread.
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
menu_open_strip_chart() {
new GtkStatsStripWindow(_monitor, 0, 0, false, 400, 100);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::menu_open_piano_roll
// Access: Protected
// Description: Open up a new piano-roll style window for the main
// thread.
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
menu_open_piano_roll() {
new GtkStatsPianoWindow(_monitor, 0, 400, 100);
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::menu_new_window
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
menu_new_window() {
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::menu_close_window
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
menu_close_window() {
destruct();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::menu_close_all_windows
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
menu_close_all_windows() {
_monitor->close_all_windows();
}
////////////////////////////////////////////////////////////////////
// Function: GtkStatsWindow::menu_disconnect
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
void GtkStatsWindow::
menu_disconnect() {
_monitor->close();
}

View File

@ -1,69 +0,0 @@
// Filename: gtkStatsWindow.h
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef GTKSTATSWINDOW_H
#define GTKSTATSWINDOW_H
#include "pandatoolbase.h"
#include "gtkStatsMonitor.h"
#include "basicGtkWindow.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : GtkStatsWindow
// Description : This is the base class for a family of windows that
// are associated with one particular stats client.
// Each window keeps a pointer back to the
// GtkStatsMonitor object, which in turn knows about all
// of the windows; when the last window is closed, the
// monitor object goes away and ends the session.
////////////////////////////////////////////////////////////////////
class GtkStatsWindow : public BasicGtkWindow {
public:
GtkStatsWindow(GtkStatsMonitor *monitor);
virtual bool destruct();
virtual void update_title();
virtual void mark_dead();
virtual void new_collector();
virtual void idle();
protected:
virtual void setup_menu();
void menu_open_strip_chart();
void menu_open_piano_roll();
virtual void menu_new_window();
void menu_close_window();
void menu_close_all_windows();
void menu_disconnect();
protected:
PT(GtkStatsMonitor) _monitor;
Gtk::VBox *_main_box;
Gtk::MenuBar *_menu;
Gtk::Menu *_file_menu;
};
#endif

View File

@ -0,0 +1,9 @@
#include "gtkStats.cxx"
#include "gtkStatsChartMenu.cxx"
#include "gtkStatsGraph.cxx"
#include "gtkStatsLabel.cxx"
#include "gtkStatsLabelStack.cxx"
#include "gtkStatsMonitor.cxx"
#include "gtkStatsPianoRoll.cxx"
#include "gtkStatsServer.cxx"
#include "gtkStatsStripChart.cxx"

View File

@ -1,201 +0,0 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Modifed for gtk-- by sac@transmeta.com */
/* Modified (slightly) for gdk-- by freyd@uni-muenster.de */
#include <gtk--/main.h>
#include <gtk--/style.h>
#include <gtk--/window.h>
#include <gtk--/button.h>
#include <gtk--/box.h>
#include <gtk--/drawingarea.h>
#include <iostream>
class ScribbleDrawingArea : public Gtk::DrawingArea
{
/* Backing pixmap for drawing area */
Gdk_Pixmap pixmap;
Gdk_GC gc;
Gdk_Window win;
Gdk_Visual visual;
virtual gint configure_event_impl (GdkEventConfigure *event);
virtual gint expose_event_impl (GdkEventExpose *event);
virtual gint button_press_event_impl (GdkEventButton *event);
virtual gint motion_notify_event_impl (GdkEventMotion *event);
void draw_brush (gdouble x, gdouble y);
public:
ScribbleDrawingArea ();
};
ScribbleDrawingArea::ScribbleDrawingArea()
: Gtk::DrawingArea(), pixmap (0)
{
set_events (GDK_EXPOSURE_MASK
| GDK_LEAVE_NOTIFY_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK);
}
/* Create a new backing pixmap of the appropriate size */
int ScribbleDrawingArea::configure_event_impl (GdkEventConfigure * /* event */)
{
win = get_window();
visual = win.get_visual();
if (pixmap)
pixmap.release();
gc = get_style()->gtkobj()->white_gc;
// Gtk::Style has no access to its data members, so use gtk objekt.
// Some access functions would be nice like GtkStyle::get_white_gc() etc.
pixmap.create(get_window(), width(), height());
pixmap.draw_rectangle (gc,
TRUE,
0, 0,
width(),
height());
return TRUE;
}
/* Redraw the screen from the backing pixmap */
int ScribbleDrawingArea::expose_event_impl (GdkEventExpose *event)
{
gc = get_style()->gtkobj()->fg_gc[GTK_WIDGET_STATE (GTK_WIDGET(gtkobj()))];
// Same like above, + Gtk::Widget has set_state function but no get_state
// function.
win.draw_pixmap(gc ,
pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
/* Draw a rectangle on the screen */
void ScribbleDrawingArea::draw_brush (gdouble x, gdouble y)
{
GdkRectangle update_rect;
update_rect.x = (int)x - 5;
update_rect.y = (int)y - 5;
update_rect.width = 10;
update_rect.height = 10;
gc = get_style()->gtkobj()->black_gc;
pixmap.draw_rectangle(
gc,
TRUE,
update_rect.x, update_rect.y,
update_rect.width, update_rect.height);
draw(&update_rect);
//draw (&update_rect);
}
gint ScribbleDrawingArea::button_press_event_impl (GdkEventButton *event)
{
if (event->button == 1 && pixmap)
draw_brush (event->x, event->y);
return TRUE;
}
gint ScribbleDrawingArea::motion_notify_event_impl (GdkEventMotion *event)
{
int x, y;
GdkModifierType state;
if (event->is_hint)
gdk_window_get_pointer (event->window, &x, &y, &state);
else
{
x = (int)event->x;
y = (int)event->y;
state = (GdkModifierType) event->state;
}
if (state & GDK_BUTTON1_MASK && pixmap)
draw_brush (x, y);
return TRUE;
}
class ScribbleWindow : public Gtk::Window
{
Gtk::VBox vbox;
ScribbleDrawingArea drawing_area;
Gtk::Button button;
void quit ();
public:
ScribbleWindow ();
};
void ScribbleWindow::quit ()
{
Gtk::Main::quit();
}
ScribbleWindow::ScribbleWindow ()
: Gtk::Window(GTK_WINDOW_TOPLEVEL),
vbox (FALSE, 0),
button ("quit")
{
add (vbox);
/* Create the drawing area */
drawing_area.size (400, 400);
vbox.pack_start (drawing_area, TRUE, TRUE, 0);
/* Add the button */
vbox.pack_start (button, FALSE, FALSE, 0);
button.clicked.connect(slot(*this, &ScribbleWindow::quit));
destroy.connect(slot(*this, &ScribbleWindow::quit));
drawing_area.show();
button.show();
vbox.show();
}
int
main (int argc, char *argv[])
{
ScribbleWindow *window;
Gtk::Main myapp(argc, argv);
window = new ScribbleWindow;
window->show();
myapp.run();
return 0;
}

View File

@ -1,18 +0,0 @@
#define BUILD_DIRECTORY $[HAVE_GTKMM]
#define USE_PACKAGES gtkmm
#begin ss_lib_target
#define TARGET gtkbase
#define LOCAL_LIBS \
progbase
#define SOURCES \
basicGtkDialog.cxx basicGtkDialog.h basicGtkWindow.cxx \
basicGtkWindow.h gtkBase.cxx gtkBase.h request_initial_size.cxx \
request_initial_size.h
#define INSTALL_HEADERS \
basicGtkDialog.h basicGtkWindow.h gtkBase.h request_initial_size.h
#end ss_lib_target

View File

@ -1,69 +0,0 @@
// Filename: basicGtkDialog.cxx
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "basicGtkDialog.h"
////////////////////////////////////////////////////////////////////
// Function: BasicGtkDialog::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BasicGtkDialog::
BasicGtkDialog(bool free_store) : BasicGtkWindow(free_store) {
_vbox = manage(new Gtk::VBox);
_action_area = manage(new Gtk::HBox);
Gtk::VBox *box0 = manage(new Gtk::VBox);
Gtk::HSeparator *hsep = manage(new Gtk::HSeparator);
add(*box0);
box0->show();
box0->pack_start(*_vbox);
_vbox->show();
box0->pack_start(*hsep);
hsep->show();
_action_area->set_border_width(10);
box0->pack_start(*_action_area, false);
_action_area->show();
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkDialog::get_vbox
// Access: Public
// Description: Returns a pointer to the main part of the dialog
// window.
////////////////////////////////////////////////////////////////////
Gtk::VBox *BasicGtkDialog::
get_vbox() const {
return _vbox;
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkDialog::get_action_area
// Access: Public
// Description: Returns a pointer to part of the dialog reserved for
// action buttons.
////////////////////////////////////////////////////////////////////
Gtk::HBox *BasicGtkDialog::
get_action_area() const {
return _action_area;
}

View File

@ -1,48 +0,0 @@
// Filename: basicGtkDialog.h
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef BASICGTKDIALOG_H
#define BASICGTKDIALOG_H
#include "basicGtkWindow.h"
#include <gtk--.h>
////////////////////////////////////////////////////////////////////
// Class : BasicGtkDialog
// Description : This looks like a wrapper around Gtk::Dialog.
// Actually, it doesn't inherit from Gtk::Dialog at all,
// but instead (indirectly) from Gtk::Window; it just
// duplicates the default functionality of Gtk::Dialog
// by defining get_vbox() and a get_action_area().
////////////////////////////////////////////////////////////////////
class BasicGtkDialog : public BasicGtkWindow {
public:
BasicGtkDialog(bool free_store = true);
Gtk::VBox *get_vbox() const;
Gtk::HBox *get_action_area() const;
private:
Gtk::VBox *_vbox;
Gtk::HBox *_action_area;
};
#endif

View File

@ -1,140 +0,0 @@
// Filename: basicGtkWindow.cxx
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "basicGtkWindow.h"
#include "gtkBase.h"
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::Constructor
// Access: Public
// Description: The free_store parameter should be true if the window
// object has been allocated from the free store (using
// new) and can be safely deleted using delete when the
// window is destroyed by the user, or false if this is
// not the case.
////////////////////////////////////////////////////////////////////
BasicGtkWindow::
BasicGtkWindow(bool free_store) : _free_store(free_store) {
_destroyed = false;
_state = S_virgin;
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BasicGtkWindow::
~BasicGtkWindow() {
destruct();
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::setup
// Access: Public
// Description: Call this after initializing the window.
////////////////////////////////////////////////////////////////////
void BasicGtkWindow::
setup() {
_state = S_setup;
_destroy_connection =
destroy.connect(slot(this, &BasicGtkWindow::window_destroyed));
show();
// Calling show() sets in motion some X events that must flow
// completely through the queue before we can safely hide() the
// thing again. To measure when this has happened, we'll drop our
// own event into the queue. When this event makes it through the
// queue, we'll assume all relevant X events have also, and it will
// be safe to hide the window.
Gtk::Main::idle.connect(slot(this, &BasicGtkWindow::idle_event));
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::destruct
// Access: Public, Virtual
// Description: Call this to remove the window, etc. It's not tied
// directly to the real destructor because that seems to
// just lead to trouble. This returns true if it
// actually destructed, or false if it had already
// destructed previously and did nothing this time.
////////////////////////////////////////////////////////////////////
bool BasicGtkWindow::
destruct() {
if (_state != S_gone) {
// We must hide the window before we destruct, or it won't disappear
// from the screen. Strange. But we also don't want to try to hide
// the window if we're destructing because of a window_destroyed
// event, so we check our little flag.
if (!_destroyed && _state != S_virgin) {
// Now, in case the window was never completely shown, we must
// wait for that to happen before we can hide it.
while (!_destroyed && _state == S_setup) {
GtkBase::_gtk->iteration();
}
if (!_destroyed) {
hide();
}
}
_state = S_gone;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::delete_self
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
void BasicGtkWindow::
delete_self() {
destruct();
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::window_destroyed
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void BasicGtkWindow::
window_destroyed() {
_destroyed = true;
destruct();
// We should probably also delete the pointer here. But maybe not.
// Gtk-- is very mysterious about this, so we'll just let it maybe
// leak.
}
////////////////////////////////////////////////////////////////////
// Function: BasicGtkWindow::idle_event
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
gint BasicGtkWindow::
idle_event() {
// Now, we're finally a bona fide window with all rights thereunto
// appertaining.
_state = S_ready;
return false;
}

View File

@ -1,60 +0,0 @@
// Filename: basicGtkWindow.h
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef BASICGTKWINDOW_H
#define BASICGTKWINDOW_H
#include <gtk--.h>
////////////////////////////////////////////////////////////////////
// Class : BasicGtkWindow
// Description : This is just a handy wrapper around Gtk::Window that
// provides some convenient setup functions.
////////////////////////////////////////////////////////////////////
class BasicGtkWindow : public Gtk::Window {
public:
BasicGtkWindow(bool free_store = true);
virtual ~BasicGtkWindow();
void setup();
virtual bool destruct();
protected:
void delete_self();
static gint static_delete(BasicGtkWindow *window);
private:
void window_destroyed();
gint idle_event();
enum State {
S_virgin,
S_setup,
S_ready,
S_gone,
};
bool _destroyed;
bool _free_store;
State _state;
SigC::Connection _destroy_connection;
};
#endif

View File

@ -1,76 +0,0 @@
// Filename: gtkBase.cxx
// Created by: drose (14Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "gtkBase.h"
#include "notify.h"
Gtk::Main *GtkBase::_gtk = NULL;
////////////////////////////////////////////////////////////////////
// Function: GtkBase::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkBase::
GtkBase() {
if (_gtk != (Gtk::Main *)NULL) {
nout << "Invalid attempt to create multiple instances of GtkBase!\n";
abort();
}
}
////////////////////////////////////////////////////////////////////
// Function: GtkBase::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GtkBase::
~GtkBase() {
nassertv(_gtk != (Gtk::Main *)NULL);
delete _gtk;
_gtk = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GtkBase::parse_command_line
// Access: Public, Virtual
// Description: This is overridden for GtkBase to give Gtk a chance
// to pull out its X-related parameters.
////////////////////////////////////////////////////////////////////
void GtkBase::
parse_command_line(int argc, char *argv[]) {
nassertv(_gtk == (Gtk::Main *)NULL);
_gtk = new Gtk::Main(argc, argv);
ProgramBase::parse_command_line(argc, argv);
}
////////////////////////////////////////////////////////////////////
// Function: GtkBase::main_loop
// Access: Public
// Description: Call this after all is set up to yield control of the
// main loop to Gtk. This normally doesn't return.
////////////////////////////////////////////////////////////////////
void GtkBase::
main_loop() {
nassertv(_gtk != NULL);
_gtk->run();
}

View File

@ -1,46 +0,0 @@
// Filename: request_initial_size.cxx
// Created by: drose (15Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "request_initial_size.h"
static int
restore_usize(Gtk::Widget *widget) {
widget->set_usize(0, 0);
return false;
}
////////////////////////////////////////////////////////////////////
// Function: request_initial_size
// Description: Gtk-- hack to request an initial size for a widget,
// while still allowing the user to resize it smaller.
////////////////////////////////////////////////////////////////////
void
request_initial_size(Gtk::Widget &widget, int xsize, int ysize) {
if (xsize != 0 || ysize != 0) {
// I can't find a way to request an initial size for a general
// widget. The best I can do is specify its minimum size.
widget.set_usize(xsize, ysize);
// However, I don't want the minimum size to be enforced forever;
// the user should be able to resize the window smaller if he wants
// to. Thus, this ugly hack: at the first idle signal, we return
// the usize to 0.
Gtk::Main::idle.connect(bind(slot(&restore_usize), &widget));
}
}

View File

@ -1,28 +0,0 @@
// Filename: request_initial_size.h
// Created by: drose (15Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef REQUEST_INITIAL_SIZE_H
#define REQUEST_INITIAL_SIZE_H
#include "pandatoolbase.h"
#include <gtk--.h>
void request_initial_size(Gtk::Widget &widget, int xsize, int ysize);
#endif