Panda3D
 All Classes Functions Variables Enumerations
winStatsMonitor.cxx
1 // Filename: winStatsMonitor.cxx
2 // Created by: drose (02Dec03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "winStatsMonitor.h"
16 #include "winStatsServer.h"
17 #include "winStatsStripChart.h"
18 #include "winStatsPianoRoll.h"
19 #include "winStatsChartMenu.h"
20 #include "winStatsMenuId.h"
21 #include "pStatGraph.h"
22 #include "pStatCollectorDef.h"
23 #include "indent.h"
24 
25 bool WinStatsMonitor::_window_class_registered = false;
26 const char * const WinStatsMonitor::_window_class_name = "monitor";
27 
28 ////////////////////////////////////////////////////////////////////
29 // Function: WinStatsMonitor::Constructor
30 // Access: Public
31 // Description:
32 ////////////////////////////////////////////////////////////////////
33 WinStatsMonitor::
34 WinStatsMonitor(WinStatsServer *server) : PStatMonitor(server) {
35  _window = 0;
36  _menu_bar = 0;
37  _options_menu = 0;
38 
39  // These will be filled in later when the menu is created.
40  _time_units = 0;
41  _scroll_speed = 0.0;
42  _pause = false;
43 }
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: WinStatsMonitor::Destructor
47 // Access: Public, Virtual
48 // Description:
49 ////////////////////////////////////////////////////////////////////
50 WinStatsMonitor::
51 ~WinStatsMonitor() {
52  Graphs::iterator gi;
53  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
54  delete (*gi);
55  }
56  _graphs.clear();
57 
58  ChartMenus::iterator mi;
59  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
60  delete (*mi);
61  }
62  _chart_menus.clear();
63 
64  if (_window) {
65  DestroyWindow(_window);
66  _window = 0;
67  }
68 
69 #ifdef DEVELOP_WINSTATS
70  // For Winstats developers, exit when the first monitor closes.
71  exit(0);
72 #endif
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: WinStatsMonitor::get_monitor_name
77 // Access: Public, Virtual
78 // Description: Should be redefined to return a descriptive name for
79 // the type of PStatsMonitor this is.
80 ////////////////////////////////////////////////////////////////////
81 string WinStatsMonitor::
83  return "WinStats";
84 }
85 
86 ////////////////////////////////////////////////////////////////////
87 // Function: WinStatsMonitor::initialized
88 // Access: Public, Virtual
89 // Description: Called after the monitor has been fully set up. At
90 // this time, it will have a valid _client_data pointer,
91 // and things like is_alive() and close() will be
92 // meaningful. However, we may not yet know who we're
93 // connected to (is_client_known() may return false),
94 // and we may not know anything about the threads or
95 // collectors we're about to get data on.
96 ////////////////////////////////////////////////////////////////////
99 }
100 
101 ////////////////////////////////////////////////////////////////////
102 // Function: WinStatsMonitor::got_hello
103 // Access: Public, Virtual
104 // Description: Called when the "hello" message has been received
105 // from the client. At this time, the client's hostname
106 // and program name will be known.
107 ////////////////////////////////////////////////////////////////////
110  create_window();
111  open_strip_chart(0, 0, false);
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: WinStatsMonitor::got_bad_version
116 // Access: Public, Virtual
117 // Description: Like got_hello(), this is called when the "hello"
118 // message has been received from the client. At this
119 // time, the client's hostname and program name will be
120 // known. However, the client appears to be an
121 // incompatible version and the connection will be
122 // terminated; the monitor should issue a message to
123 // that effect.
124 ////////////////////////////////////////////////////////////////////
126 got_bad_version(int client_major, int client_minor,
127  int server_major, int server_minor) {
128  ostringstream str;
129  str << "Unable to honor connection attempt from "
130  << get_client_progname() << " on " << get_client_hostname()
131  << ": unsupported PStats version "
132  << client_major << "." << client_minor;
133 
134  if (server_minor == 0) {
135  str << " (server understands version " << server_major
136  << "." << server_minor << " only).";
137  } else {
138  str << " (server understands versions " << server_major
139  << ".0 through " << server_major << "." << server_minor << ").";
140  }
141 
142  string message = str.str();
143  MessageBox(NULL, message.c_str(), "Bad version",
144  MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: WinStatsMonitor::new_collector
149 // Access: Public, Virtual
150 // Description: Called whenever a new Collector definition is
151 // received from the client. Generally, the client will
152 // send all of its collectors over shortly after
153 // connecting, but there's no guarantee that they will
154 // all be received before the first frames are received.
155 // The monitor should be prepared to accept new Collector
156 // definitions midstream.
157 ////////////////////////////////////////////////////////////////////
159 new_collector(int collector_index) {
160  Graphs::iterator gi;
161  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
162  WinStatsGraph *graph = (*gi);
163  graph->new_collector(collector_index);
164  }
165 
166  // We might need to update our menus.
167  ChartMenus::iterator mi;
168  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
169  (*mi)->do_update();
170  }
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: WinStatsMonitor::new_thread
175 // Access: Public, Virtual
176 // Description: Called whenever a new Thread definition is
177 // received from the client. Generally, the client will
178 // send all of its threads over shortly after
179 // connecting, but there's no guarantee that they will
180 // all be received before the first frames are received.
181 // The monitor should be prepared to accept new Thread
182 // definitions midstream.
183 ////////////////////////////////////////////////////////////////////
185 new_thread(int thread_index) {
186  WinStatsChartMenu *chart_menu = new WinStatsChartMenu(this, thread_index);
187  chart_menu->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
188  _chart_menus.push_back(chart_menu);
189  DrawMenuBar(_window);
190 }
191 
192 ////////////////////////////////////////////////////////////////////
193 // Function: WinStatsMonitor::new_data
194 // Access: Public, Virtual
195 // Description: Called as each frame's data is made available. There
196 // is no guarantee the frames will arrive in order, or
197 // that all of them will arrive at all. The monitor
198 // should be prepared to accept frames received
199 // out-of-order or missing.
200 ////////////////////////////////////////////////////////////////////
202 new_data(int thread_index, int frame_number) {
203  Graphs::iterator gi;
204  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
205  WinStatsGraph *graph = (*gi);
206  graph->new_data(thread_index, frame_number);
207  }
208 }
209 
210 
211 ////////////////////////////////////////////////////////////////////
212 // Function: WinStatsMonitor::lost_connection
213 // Access: Public, Virtual
214 // Description: Called whenever the connection to the client has been
215 // lost. This is a permanent state change. The monitor
216 // should update its display to represent this, and may
217 // choose to close down automatically.
218 ////////////////////////////////////////////////////////////////////
221  nout << "Lost connection to " << get_client_hostname() << "\n";
222 
223  if (_window) {
224  DestroyWindow(_window);
225  _window = 0;
226  }
227 }
228 
229 ////////////////////////////////////////////////////////////////////
230 // Function: WinStatsMonitor::idle
231 // Access: Public, Virtual
232 // Description: If has_idle() returns true, this will be called
233 // periodically to allow the monitor to update its
234 // display or whatever it needs to do.
235 ////////////////////////////////////////////////////////////////////
237 idle() {
238  // Check if any of our chart menus need updating.
239  ChartMenus::iterator mi;
240  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
241  (*mi)->check_update();
242  }
243 
244  // Update the frame rate label from the main thread (thread 0).
245  const PStatThreadData *thread_data = get_client_data()->get_thread_data(0);
246  double frame_rate = thread_data->get_frame_rate();
247  if (frame_rate != 0.0f) {
248  char buffer[128];
249  sprintf(buffer, "%0.1f ms / %0.1f Hz", 1000.0f / frame_rate, frame_rate);
250 
251  MENUITEMINFO mii;
252  memset(&mii, 0, sizeof(mii));
253  mii.cbSize = sizeof(mii);
254  mii.fMask = MIIM_STRING;
255  mii.dwTypeData = buffer;
256  SetMenuItemInfo(_menu_bar, MI_frame_rate_label, FALSE, &mii);
257  DrawMenuBar(_window);
258  }
259 }
260 
261 ////////////////////////////////////////////////////////////////////
262 // Function: WinStatsMonitor::has_idle
263 // Access: Public, Virtual
264 // Description: Should be redefined to return true if you want to
265 // redefine idle() and expect it to be called.
266 ////////////////////////////////////////////////////////////////////
269  return true;
270 }
271 
272 ////////////////////////////////////////////////////////////////////
273 // Function: WinStatsMonitor::user_guide_bars_changed
274 // Access: Public, Virtual
275 // Description: Called when the user guide bars have been changed.
276 ////////////////////////////////////////////////////////////////////
279  Graphs::iterator gi;
280  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
281  WinStatsGraph *graph = (*gi);
282  graph->user_guide_bars_changed();
283  }
284 }
285 
286 ////////////////////////////////////////////////////////////////////
287 // Function: WinStatsMonitor::get_window
288 // Access: Public
289 // Description: Returns the window handle to the monitor's window.
290 ////////////////////////////////////////////////////////////////////
292 get_window() const {
293  return _window;
294 }
295 
296 ////////////////////////////////////////////////////////////////////
297 // Function: WinStatsMonitor::open_strip_chart
298 // Access: Public
299 // Description: Opens a new strip chart showing the indicated data.
300 ////////////////////////////////////////////////////////////////////
302 open_strip_chart(int thread_index, int collector_index, bool show_level) {
303  WinStatsStripChart *graph =
304  new WinStatsStripChart(this, thread_index, collector_index, show_level);
305  add_graph(graph);
306 
307  graph->set_time_units(_time_units);
308  graph->set_scroll_speed(_scroll_speed);
309  graph->set_pause(_pause);
310 }
311 
312 ////////////////////////////////////////////////////////////////////
313 // Function: WinStatsMonitor::open_piano_roll
314 // Access: Public
315 // Description: Opens a new piano roll showing the indicated data.
316 ////////////////////////////////////////////////////////////////////
318 open_piano_roll(int thread_index) {
319  WinStatsPianoRoll *graph = new WinStatsPianoRoll(this, thread_index);
320  add_graph(graph);
321 
322  graph->set_time_units(_time_units);
323  graph->set_scroll_speed(_scroll_speed);
324  graph->set_pause(_pause);
325 }
326 
327 ////////////////////////////////////////////////////////////////////
328 // Function: WinStatsMonitor::lookup_menu
329 // Access: Public
330 // Description: Returns the MenuDef properties associated with the
331 // indicated menu ID. This specifies what we expect to
332 // do when the given menu has been selected.
333 ////////////////////////////////////////////////////////////////////
335 lookup_menu(int menu_id) const {
336  static MenuDef invalid(0, 0, false);
337  int menu_index = menu_id - MI_new_chart;
338  nassertr(menu_index >= 0 && menu_index < (int)_menu_by_id.size(), invalid);
339  return _menu_by_id[menu_index];
340 }
341 
342 ////////////////////////////////////////////////////////////////////
343 // Function: WinStatsMonitor::get_menu_id
344 // Access: Public
345 // Description: Returns the menu ID that is reserved for the
346 // indicated MenuDef properties. If this is the first
347 // time these particular properties have been requested,
348 // a new menu ID is returned; otherwise, the existing
349 // menu ID is returned.
350 ////////////////////////////////////////////////////////////////////
352 get_menu_id(const MenuDef &menu_def) {
353  MenuByDef::iterator mi;
354  mi = _menu_by_def.find(menu_def);
355  if (mi != _menu_by_def.end()) {
356  return (*mi).second;
357  }
358 
359  // Slot a new id.
360  int menu_id = (int)_menu_by_id.size() + MI_new_chart;
361  _menu_by_id.push_back(menu_def);
362  _menu_by_def[menu_def] = menu_id;
363 
364  return menu_id;
365 }
366 
367 ////////////////////////////////////////////////////////////////////
368 // Function: WinStatsMonitor::set_time_units
369 // Access: Public
370 // Description: Called when the user selects a new time units from
371 // the monitor pulldown menu, this should adjust the
372 // units for all graphs to the indicated mask if it is a
373 // time-based graph.
374 ////////////////////////////////////////////////////////////////////
376 set_time_units(int unit_mask) {
377  _time_units = unit_mask;
378 
379  // First, change all of the open graphs appropriately.
380  Graphs::iterator gi;
381  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
382  WinStatsGraph *graph = (*gi);
383  graph->set_time_units(_time_units);
384  }
385 
386  // Now change the checkmark on the pulldown menu.
387  MENUITEMINFO mii;
388  memset(&mii, 0, sizeof(mii));
389  mii.cbSize = sizeof(mii);
390  mii.fMask = MIIM_STATE;
391 
392  mii.fState = ((_time_units & PStatGraph::GBU_ms) != 0) ?
393  MFS_CHECKED : MFS_UNCHECKED;
394  SetMenuItemInfo(_options_menu, MI_time_ms, FALSE, &mii);
395 
396  mii.fState = ((_time_units & PStatGraph::GBU_hz) != 0) ?
397  MFS_CHECKED : MFS_UNCHECKED;
398  SetMenuItemInfo(_options_menu, MI_time_hz, FALSE, &mii);
399 }
400 
401 ////////////////////////////////////////////////////////////////////
402 // Function: WinStatsMonitor::set_scroll_speed
403 // Access: Public
404 // Description: Called when the user selects a new scroll speed from
405 // the monitor pulldown menu, this should adjust the
406 // speeds for all graphs to the indicated value.
407 ////////////////////////////////////////////////////////////////////
409 set_scroll_speed(double scroll_speed) {
410  _scroll_speed = scroll_speed;
411 
412  // First, change all of the open graphs appropriately.
413  Graphs::iterator gi;
414  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
415  WinStatsGraph *graph = (*gi);
416  graph->set_scroll_speed(_scroll_speed);
417  }
418 
419  // Now change the checkmark on the pulldown menu.
420  MENUITEMINFO mii;
421  memset(&mii, 0, sizeof(mii));
422  mii.cbSize = sizeof(mii);
423  mii.fMask = MIIM_STATE;
424 
425  mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 1.0, 0.1) ?
426  MFS_CHECKED : MFS_UNCHECKED;
427  SetMenuItemInfo(_speed_menu, MI_speed_1, FALSE, &mii);
428 
429  mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 2.0, 0.1) ?
430  MFS_CHECKED : MFS_UNCHECKED;
431  SetMenuItemInfo(_speed_menu, MI_speed_2, FALSE, &mii);
432 
433  mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 3.0, 0.1) ?
434  MFS_CHECKED : MFS_UNCHECKED;
435  SetMenuItemInfo(_speed_menu, MI_speed_3, FALSE, &mii);
436 
437  mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 6.0, 0.1) ?
438  MFS_CHECKED : MFS_UNCHECKED;
439  SetMenuItemInfo(_speed_menu, MI_speed_6, FALSE, &mii);
440 
441  mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 12.0, 0.1) ?
442  MFS_CHECKED : MFS_UNCHECKED;
443  SetMenuItemInfo(_speed_menu, MI_speed_12, FALSE, &mii);
444 }
445 
446 ////////////////////////////////////////////////////////////////////
447 // Function: WinStatsMonitor::set_pause
448 // Access: Public
449 // Description: Called when the user selects a pause on or pause off
450 // option from the menu.
451 ////////////////////////////////////////////////////////////////////
453 set_pause(bool pause) {
454  _pause = pause;
455 
456  // First, change all of the open graphs appropriately.
457  Graphs::iterator gi;
458  for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
459  WinStatsGraph *graph = (*gi);
460  graph->set_pause(_pause);
461  }
462 
463  // Now change the checkmark on the pulldown menu.
464  MENUITEMINFO mii;
465  memset(&mii, 0, sizeof(mii));
466  mii.cbSize = sizeof(mii);
467  mii.fMask = MIIM_STATE;
468 
469  mii.fState = _pause ? MFS_CHECKED : MFS_UNCHECKED;
470  SetMenuItemInfo(_speed_menu, MI_pause, FALSE, &mii);
471 }
472 
473 ////////////////////////////////////////////////////////////////////
474 // Function: WinStatsMonitor::add_graph
475 // Access: Private
476 // Description: Adds the newly-created graph to the list of managed
477 // graphs.
478 ////////////////////////////////////////////////////////////////////
479 void WinStatsMonitor::
480 add_graph(WinStatsGraph *graph) {
481  _graphs.insert(graph);
482 }
483 
484 ////////////////////////////////////////////////////////////////////
485 // Function: WinStatsMonitor::remove_graph
486 // Access: Private
487 // Description: Deletes the indicated graph.
488 ////////////////////////////////////////////////////////////////////
489 void WinStatsMonitor::
490 remove_graph(WinStatsGraph *graph) {
491  Graphs::iterator gi = _graphs.find(graph);
492  if (gi != _graphs.end()) {
493  _graphs.erase(gi);
494  delete graph;
495  }
496 }
497 
498 ////////////////////////////////////////////////////////////////////
499 // Function: WinStatsMonitor::create_window
500 // Access: Private
501 // Description: Creates the window for this monitor.
502 ////////////////////////////////////////////////////////////////////
503 void WinStatsMonitor::
504 create_window() {
505  if (_window) {
506  return;
507  }
508 
509  HINSTANCE application = GetModuleHandle(NULL);
510  register_window_class(application);
511 
512  _menu_bar = CreateMenu();
513 
514  setup_options_menu();
515  setup_speed_menu();
516  setup_frame_rate_label();
517 
518  ChartMenus::iterator mi;
519  for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
520  (*mi)->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
521  }
522 
523  _window_title = get_client_progname() + " on " + get_client_hostname();
524  DWORD window_style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
525  WS_CLIPSIBLINGS | WS_VISIBLE;
526 
527  _window =
528  CreateWindow(_window_class_name, _window_title.c_str(), window_style,
529  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
530  NULL, _menu_bar, application, 0);
531  if (!_window) {
532  nout << "Could not create monitor window!\n";
533  exit(1);
534  }
535 
536  SetWindowLongPtr(_window, 0, (LONG_PTR)this);
537 
538  // For some reason, SW_SHOWNORMAL doesn't always work, but
539  // SW_RESTORE seems to.
540  ShowWindow(_window, SW_RESTORE);
541  SetForegroundWindow(_window);
542 }
543 
544 ////////////////////////////////////////////////////////////////////
545 // Function: WinStatsMonitor::setup_options_menu
546 // Access: Private
547 // Description: Creates the "Options" pulldown menu.
548 ////////////////////////////////////////////////////////////////////
549 void WinStatsMonitor::
550 setup_options_menu() {
551  _options_menu = CreatePopupMenu();
552 
553  MENUITEMINFO mii;
554  memset(&mii, 0, sizeof(mii));
555  mii.cbSize = sizeof(mii);
556 
557  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
558  mii.fType = MFT_STRING;
559  mii.hSubMenu = _options_menu;
560 
561  // One day, when there is more than one option here, we will
562  // actually present this to the user as the "Options" menu. For
563  // now, the only option we have is time units.
564  //mii.dwTypeData = "Options";
565  mii.dwTypeData = "Units";
566  InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
567 
568 
569  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
570  mii.fType = MFT_STRING | MFT_RADIOCHECK;
571  mii.hbmpChecked = NULL;
572  mii.hbmpUnchecked = NULL;
573  mii.fState = MFS_UNCHECKED;
574  mii.wID = MI_time_ms;
575  mii.dwTypeData = "ms";
576  InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii);
577 
578  mii.wID = MI_time_hz;
579  mii.dwTypeData = "Hz";
580  InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii);
581 
582  set_time_units(PStatGraph::GBU_ms);
583 }
584 
585 ////////////////////////////////////////////////////////////////////
586 // Function: WinStatsMonitor::setup_speed_menu
587 // Access: Private
588 // Description: Creates the "Speed" pulldown menu.
589 ////////////////////////////////////////////////////////////////////
590 void WinStatsMonitor::
591 setup_speed_menu() {
592  _speed_menu = CreatePopupMenu();
593 
594  MENUITEMINFO mii;
595  memset(&mii, 0, sizeof(mii));
596  mii.cbSize = sizeof(mii);
597 
598  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
599  mii.fType = MFT_STRING;
600  mii.hSubMenu = _speed_menu;
601  mii.dwTypeData = "Speed";
602  InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
603 
604 
605  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
606  mii.fType = MFT_STRING | MFT_RADIOCHECK;
607  mii.hbmpChecked = NULL;
608  mii.hbmpUnchecked = NULL;
609  mii.fState = MFS_UNCHECKED;
610  mii.wID = MI_speed_1;
611  mii.dwTypeData = "1";
612  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
613 
614  mii.wID = MI_speed_2;
615  mii.dwTypeData = "2";
616  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
617 
618  mii.wID = MI_speed_3;
619  mii.dwTypeData = "3";
620  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
621 
622  mii.wID = MI_speed_6;
623  mii.dwTypeData = "6";
624  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
625 
626  mii.wID = MI_speed_12;
627  mii.dwTypeData = "12";
628  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
629 
630  mii.fMask = MIIM_FTYPE;
631  mii.fType = MFT_SEPARATOR;
632  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
633 
634  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
635  mii.fType = MFT_STRING;
636  mii.wID = MI_pause;
637  mii.dwTypeData = "pause";
638  InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
639 
640  set_scroll_speed(3);
641  set_pause(false);
642 }
643 
644 ////////////////////////////////////////////////////////////////////
645 // Function: WinStatsMonitor::setup_frame_rate_label
646 // Access: Private
647 // Description: Creates the frame rate label on the right end of the
648 // menu bar. This is used as a text label to display
649 // the main thread's frame rate to the user, although it
650 // is implemented as a right-justified toplevel menu
651 // item that doesn't open to anything.
652 ////////////////////////////////////////////////////////////////////
653 void WinStatsMonitor::
654 setup_frame_rate_label() {
655  MENUITEMINFO mii;
656  memset(&mii, 0, sizeof(mii));
657  mii.cbSize = sizeof(mii);
658 
659  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
660  mii.fType = MFT_STRING | MFT_RIGHTJUSTIFY;
661  mii.wID = MI_frame_rate_label;
662  mii.dwTypeData = "";
663  InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
664 }
665 
666 ////////////////////////////////////////////////////////////////////
667 // Function: WinStatsMonitor::register_window_class
668 // Access: Private, Static
669 // Description: Registers the window class for the monitor window, if
670 // it has not already been registered.
671 ////////////////////////////////////////////////////////////////////
672 void WinStatsMonitor::
673 register_window_class(HINSTANCE application) {
674  if (_window_class_registered) {
675  return;
676  }
677 
678  WNDCLASS wc;
679 
680  ZeroMemory(&wc, sizeof(WNDCLASS));
681  wc.style = 0;
682  wc.lpfnWndProc = (WNDPROC)static_window_proc;
683  wc.hInstance = application;
684  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
685  wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
686  wc.lpszMenuName = NULL;
687  wc.lpszClassName = _window_class_name;
688 
689  // Reserve space to associate the this pointer with the window.
690  wc.cbWndExtra = sizeof(WinStatsMonitor *);
691 
692  if (!RegisterClass(&wc)) {
693  nout << "Could not register monitor window class!\n";
694  exit(1);
695  }
696 
697  _window_class_registered = true;
698 }
699 
700 ////////////////////////////////////////////////////////////////////
701 // Function: WinStatsMonitor::static_window_proc
702 // Access: Private, Static
703 // Description:
704 ////////////////////////////////////////////////////////////////////
705 LONG WINAPI WinStatsMonitor::
706 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
707  WinStatsMonitor *self = (WinStatsMonitor *)GetWindowLongPtr(hwnd, 0);
708  if (self != (WinStatsMonitor *)NULL && self->_window == hwnd) {
709  return self->window_proc(hwnd, msg, wparam, lparam);
710  } else {
711  return DefWindowProc(hwnd, msg, wparam, lparam);
712  }
713 }
714 
715 ////////////////////////////////////////////////////////////////////
716 // Function: WinStatsMonitor::window_proc
717 // Access: Private
718 // Description:
719 ////////////////////////////////////////////////////////////////////
720 LONG WinStatsMonitor::
721 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
722  switch (msg) {
723  case WM_DESTROY:
724  close();
725  break;
726 
727  case WM_COMMAND:
728  if (HIWORD(wparam) <= 1) {
729  int menu_id = LOWORD(wparam);
730  handle_menu_command(menu_id);
731  return 0;
732  }
733  break;
734 
735  default:
736  break;
737  }
738 
739  return DefWindowProc(hwnd, msg, wparam, lparam);
740 }
741 
742 ////////////////////////////////////////////////////////////////////
743 // Function: WinStatsMonitor::handle_menu_command
744 // Access: Private
745 // Description:
746 ////////////////////////////////////////////////////////////////////
747 void WinStatsMonitor::
748 handle_menu_command(int menu_id) {
749  switch (menu_id) {
750  case MI_none:
751  break;
752 
753  case MI_time_ms:
754  set_time_units(PStatGraph::GBU_ms);
755  break;
756 
757  case MI_time_hz:
758  set_time_units(PStatGraph::GBU_hz);
759  break;
760 
761  case MI_speed_1:
762  set_scroll_speed(1);
763  break;
764 
765  case MI_speed_2:
766  set_scroll_speed(2);
767  break;
768 
769  case MI_speed_3:
770  set_scroll_speed(3);
771  break;
772 
773  case MI_speed_6:
774  set_scroll_speed(6);
775  break;
776 
777  case MI_speed_12:
778  set_scroll_speed(12);
779  break;
780 
781  case MI_pause:
782  set_pause(!_pause);
783  break;
784 
785  default:
786  if (menu_id >= MI_new_chart) {
787  const MenuDef &menu_def = lookup_menu(menu_id);
788  if (menu_def._collector_index < 0) {
789  open_piano_roll(menu_def._thread_index);
790  } else {
791  open_strip_chart(menu_def._thread_index, menu_def._collector_index,
792  menu_def._show_level);
793  }
794  }
795  }
796 }
string get_client_progname() const
Returns the program name of the client we&#39;re connected to, if known.
Definition: pStatMonitor.I:86
virtual void new_collector(int collector_index)
Called whenever a new Collector definition is received from the client.
virtual string get_monitor_name()
Should be redefined to return a descriptive name for the type of PStatsMonitor this is...
A window that draws a strip chart, given a view.
The class that owns the main loop, waiting for client connections.
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 ...
const MenuDef & lookup_menu(int menu_id) const
Returns the MenuDef properties associated with the indicated menu ID.
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&#39;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.
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...
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...
Definition: pStatMonitor.h:43
string get_client_hostname() const
Returns the hostname of the client we&#39;re connected to, if known.
Definition: pStatMonitor.I:72
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 ...
Definition: winStatsGraph.h:32
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 &quot;hello&quot; 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.
A pulldown menu of charts available for a particular thread.
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 ...
void add_to_menu_bar(HMENU menu_bar, int before_menu_id)
Adds the menu to the end of the indicated menu bar.
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...
const PStatClientData * get_client_data() const
Returns the client data associated with this monitor.
Definition: pStatMonitor.I:32
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.
int get_menu_id(const MenuDef &menu_def)
Returns the menu ID that is reserved for the indicated MenuDef properties.
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.
HWND get_window() const
Returns the window handle to the monitor&#39;s window.
double get_frame_rate() const
Computes the average frame rate over the past pstats_average_time seconds, by counting up the number ...
virtual void got_hello()
Called when the &quot;hello&quot; message has been received from the client.