24 bool WinStatsMonitor::_window_class_registered =
false;
25 const char *
const WinStatsMonitor::_window_class_name =
"monitor";
48 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
53 ChartMenus::iterator mi;
54 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
60 DestroyWindow(_window);
64 #ifdef DEVELOP_WINSTATS 109 int server_major,
int server_minor) {
110 std::ostringstream str;
111 str <<
"Unable to honor connection attempt from " 113 <<
": unsupported PStats version " 114 << client_major <<
"." << client_minor;
116 if (server_minor == 0) {
117 str <<
" (server understands version " << server_major
118 <<
"." << server_minor <<
" only).";
120 str <<
" (server understands versions " << server_major
121 <<
".0 through " << server_major <<
"." << server_minor <<
").";
124 std::string message = str.str();
125 MessageBox(
nullptr, message.c_str(),
"Bad version",
126 MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
139 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
145 ChartMenus::iterator mi;
146 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
162 _chart_menus.push_back(chart_menu);
163 DrawMenuBar(_window);
175 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
177 graph->
new_data(thread_index, frame_number);
192 DestroyWindow(_window);
204 ChartMenus::iterator mi;
205 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
206 (*mi)->check_update();
212 if (frame_rate != 0.0f) {
214 sprintf(buffer,
"%0.1f ms / %0.1f Hz", 1000.0f / frame_rate, frame_rate);
217 memset(&mii, 0,
sizeof(mii));
218 mii.cbSize =
sizeof(mii);
219 mii.fMask = MIIM_STRING;
220 mii.dwTypeData = buffer;
221 SetMenuItemInfo(_menu_bar, MI_frame_rate_label, FALSE, &mii);
222 DrawMenuBar(_window);
241 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
288 static MenuDef invalid(0, 0,
false);
289 int menu_index = menu_id - MI_new_chart;
290 nassertr(menu_index >= 0 && menu_index < (
int)_menu_by_id.size(), invalid);
291 return _menu_by_id[menu_index];
301 MenuByDef::iterator mi;
302 mi = _menu_by_def.find(menu_def);
303 if (mi != _menu_by_def.end()) {
308 int menu_id = (int)_menu_by_id.size() + MI_new_chart;
309 _menu_by_id.push_back(menu_def);
310 _menu_by_def[menu_def] = menu_id;
322 _time_units = unit_mask;
326 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
333 memset(&mii, 0,
sizeof(mii));
334 mii.cbSize =
sizeof(mii);
335 mii.fMask = MIIM_STATE;
337 mii.fState = ((_time_units & PStatGraph::GBU_ms) != 0) ?
338 MFS_CHECKED : MFS_UNCHECKED;
339 SetMenuItemInfo(_options_menu, MI_time_ms, FALSE, &mii);
341 mii.fState = ((_time_units & PStatGraph::GBU_hz) != 0) ?
342 MFS_CHECKED : MFS_UNCHECKED;
343 SetMenuItemInfo(_options_menu, MI_time_hz, FALSE, &mii);
352 _scroll_speed = scroll_speed;
356 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
363 memset(&mii, 0,
sizeof(mii));
364 mii.cbSize =
sizeof(mii);
365 mii.fMask = MIIM_STATE;
367 mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 1.0, 0.1) ?
368 MFS_CHECKED : MFS_UNCHECKED;
369 SetMenuItemInfo(_speed_menu, MI_speed_1, FALSE, &mii);
371 mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 2.0, 0.1) ?
372 MFS_CHECKED : MFS_UNCHECKED;
373 SetMenuItemInfo(_speed_menu, MI_speed_2, FALSE, &mii);
375 mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 3.0, 0.1) ?
376 MFS_CHECKED : MFS_UNCHECKED;
377 SetMenuItemInfo(_speed_menu, MI_speed_3, FALSE, &mii);
379 mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 6.0, 0.1) ?
380 MFS_CHECKED : MFS_UNCHECKED;
381 SetMenuItemInfo(_speed_menu, MI_speed_6, FALSE, &mii);
383 mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 12.0, 0.1) ?
384 MFS_CHECKED : MFS_UNCHECKED;
385 SetMenuItemInfo(_speed_menu, MI_speed_12, FALSE, &mii);
397 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
404 memset(&mii, 0,
sizeof(mii));
405 mii.cbSize =
sizeof(mii);
406 mii.fMask = MIIM_STATE;
408 mii.fState = _pause ? MFS_CHECKED : MFS_UNCHECKED;
409 SetMenuItemInfo(_speed_menu, MI_pause, FALSE, &mii);
415 void WinStatsMonitor::
417 _graphs.insert(graph);
423 void WinStatsMonitor::
425 Graphs::iterator gi = _graphs.find(graph);
426 if (gi != _graphs.end()) {
435 void WinStatsMonitor::
441 HINSTANCE application = GetModuleHandle(
nullptr);
442 register_window_class(application);
444 _menu_bar = CreateMenu();
446 setup_options_menu();
448 setup_frame_rate_label();
450 ChartMenus::iterator mi;
451 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
452 (*mi)->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
456 DWORD window_style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
457 WS_CLIPSIBLINGS | WS_VISIBLE;
460 CreateWindow(_window_class_name, _window_title.c_str(), window_style,
461 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
462 nullptr, _menu_bar, application, 0);
464 nout <<
"Could not create monitor window!\n";
468 SetWindowLongPtr(_window, 0, (LONG_PTR)
this);
472 ShowWindow(_window, SW_RESTORE);
473 SetForegroundWindow(_window);
479 void WinStatsMonitor::
480 setup_options_menu() {
481 _options_menu = CreatePopupMenu();
484 memset(&mii, 0,
sizeof(mii));
485 mii.cbSize =
sizeof(mii);
487 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
488 mii.fType = MFT_STRING;
489 mii.hSubMenu = _options_menu;
494 mii.dwTypeData =
"Units";
495 InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
498 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
499 mii.fType = MFT_STRING | MFT_RADIOCHECK;
500 mii.hbmpChecked =
nullptr;
501 mii.hbmpUnchecked =
nullptr;
502 mii.fState = MFS_UNCHECKED;
503 mii.wID = MI_time_ms;
504 mii.dwTypeData =
"ms";
505 InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii);
507 mii.wID = MI_time_hz;
508 mii.dwTypeData =
"Hz";
509 InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii);
517 void WinStatsMonitor::
519 _speed_menu = CreatePopupMenu();
522 memset(&mii, 0,
sizeof(mii));
523 mii.cbSize =
sizeof(mii);
525 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
526 mii.fType = MFT_STRING;
527 mii.hSubMenu = _speed_menu;
528 mii.dwTypeData =
"Speed";
529 InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
532 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
533 mii.fType = MFT_STRING | MFT_RADIOCHECK;
534 mii.hbmpChecked =
nullptr;
535 mii.hbmpUnchecked =
nullptr;
536 mii.fState = MFS_UNCHECKED;
537 mii.wID = MI_speed_1;
538 mii.dwTypeData =
"1";
539 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
541 mii.wID = MI_speed_2;
542 mii.dwTypeData =
"2";
543 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
545 mii.wID = MI_speed_3;
546 mii.dwTypeData =
"3";
547 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
549 mii.wID = MI_speed_6;
550 mii.dwTypeData =
"6";
551 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
553 mii.wID = MI_speed_12;
554 mii.dwTypeData =
"12";
555 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
557 mii.fMask = MIIM_FTYPE;
558 mii.fType = MFT_SEPARATOR;
559 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
561 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
562 mii.fType = MFT_STRING;
564 mii.dwTypeData =
"pause";
565 InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
577 void WinStatsMonitor::
578 setup_frame_rate_label() {
580 memset(&mii, 0,
sizeof(mii));
581 mii.cbSize =
sizeof(mii);
583 mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
584 mii.fType = MFT_STRING | MFT_RIGHTJUSTIFY;
585 mii.wID = MI_frame_rate_label;
587 InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
594 void WinStatsMonitor::
595 register_window_class(HINSTANCE application) {
596 if (_window_class_registered) {
602 ZeroMemory(&wc,
sizeof(WNDCLASS));
604 wc.lpfnWndProc = (WNDPROC)static_window_proc;
605 wc.hInstance = application;
606 wc.hCursor = LoadCursor(
nullptr, IDC_ARROW);
607 wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
608 wc.lpszMenuName =
nullptr;
609 wc.lpszClassName = _window_class_name;
614 if (!RegisterClass(&wc)) {
615 nout <<
"Could not register monitor window class!\n";
619 _window_class_registered =
true;
625 LONG WINAPI WinStatsMonitor::
626 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
628 if (
self !=
nullptr && self->_window == hwnd) {
629 return self->window_proc(hwnd, msg, wparam, lparam);
631 return DefWindowProc(hwnd, msg, wparam, lparam);
638 LONG WinStatsMonitor::
639 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
646 if (HIWORD(wparam) <= 1) {
647 int menu_id = LOWORD(wparam);
648 handle_menu_command(menu_id);
657 return DefWindowProc(hwnd, msg, wparam, lparam);
663 void WinStatsMonitor::
664 handle_menu_command(
int menu_id) {
702 if (menu_id >= MI_new_chart) {
704 if (menu_def._collector_index < 0) {
708 menu_def._show_level);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void new_collector(int collector_index)
Called whenever a new Collector definition is received from the client.
A window that draws a strip chart, given a view.
The class that owns the main loop, waiting for client connections.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_time_units(int unit_mask)
Called when the user selects a new time units from the monitor pulldown menu, this should adjust the ...
virtual void set_scroll_speed(double scroll_speed)
Called when the user selects a new scroll speed from the monitor pulldown menu, this should adjust th...
void close()
Closes the client connection if it is active.
virtual void new_thread(int thread_index)
Called whenever a new Thread definition is received from the client.
virtual void new_data(int thread_index, int frame_number)
Called as each frame's data is made available.
virtual void set_time_units(int unit_mask)
Called when the user selects a new time units from the monitor pulldown menu, this should adjust the ...
void user_guide_bars_changed()
Called when the user guide bars have been changed.
std::string get_client_hostname() const
Returns the hostname of the client we're connected to, if known.
void open_strip_chart(int thread_index, int collector_index, bool show_level)
Opens a new strip chart showing the indicated data.
virtual void lost_connection()
Called whenever the connection to the client has been lost.
virtual bool has_idle()
Should be redefined to return true if you want to redefine idle() and expect it to be called.
void set_scroll_speed(double scroll_speed)
Called when the user selects a new scroll speed from the monitor pulldown menu, this should adjust th...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void set_time_units(int unit_mask)
Called when the user selects a new time units from the monitor pulldown menu, this should adjust the ...
This is an abstract class that presents the interface to any number of different front-ends for the s...
virtual void set_scroll_speed(double scroll_speed)
Called when the user selects a new scroll speed from the monitor pulldown menu, this should adjust th...
This is just an abstract base class to provide a common pointer type for the various kinds of graphs ...
virtual void got_bad_version(int client_major, int client_minor, int server_major, int server_minor)
Like got_hello(), this is called when the "hello" message has been received from the client.
void set_pause(bool pause)
Called when the user selects a pause on or pause off option from the menu.
virtual void initialized()
Called after the monitor has been fully set up.
double get_frame_rate() const
Computes the average frame rate over the past pstats_average_time seconds, by counting up the number ...
std::string get_client_progname() const
Returns the program name of the client we're connected to, if known.
virtual void new_collector(int collector_index)
Called whenever a new Collector definition is received from the client.
virtual void set_time_units(int unit_mask)
Called when the user selects a new time units from the monitor pulldown menu, this should adjust the ...
A collection of FrameData structures for recently-received frames within a particular thread.
This class represents a connection to a PStatsClient and manages the data exchange with the client.
virtual std::string get_monitor_name()
Should be redefined to return a descriptive name for the type of PStatsMonitor this is.
const PStatThreadData * get_thread_data(int index) const
Returns the data associated with the indicated thread.
void set_pause(bool pause)
Changes the pause flag for the graph.
A window that draws a piano-roll style chart, which shows the collectors explicitly stopping and star...
virtual void idle()
If has_idle() returns true, this will be called periodically to allow the monitor to update its displ...
virtual void new_data(int thread_index, int frame_number)
Called whenever new data arrives.
const MenuDef & lookup_menu(int menu_id) const
Returns the MenuDef properties associated with the indicated menu ID.
int get_menu_id(const MenuDef &menu_def)
Returns the menu ID that is reserved for the indicated MenuDef properties.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void open_piano_roll(int thread_index)
Opens a new piano roll showing the indicated data.
virtual void user_guide_bars_changed()
Called when the user guide bars have been changed.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const PStatClientData * get_client_data() const
Returns the client data associated with this monitor.
HWND get_window() const
Returns the window handle to the monitor's window.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void got_hello()
Called when the "hello" message has been received from the client.