Panda3D
 All Classes Functions Variables Enumerations
winStatsMonitor.cxx
00001 // Filename: winStatsMonitor.cxx
00002 // Created by:  drose (02Dec03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "winStatsMonitor.h"
00016 #include "winStatsServer.h"
00017 #include "winStatsStripChart.h"
00018 #include "winStatsPianoRoll.h"
00019 #include "winStatsChartMenu.h"
00020 #include "winStatsMenuId.h"
00021 #include "pStatGraph.h"
00022 #include "pStatCollectorDef.h"
00023 #include "indent.h"
00024 
00025 bool WinStatsMonitor::_window_class_registered = false;
00026 const char * const WinStatsMonitor::_window_class_name = "monitor";
00027 
00028 ////////////////////////////////////////////////////////////////////
00029 //     Function: WinStatsMonitor::Constructor
00030 //       Access: Public
00031 //  Description:
00032 ////////////////////////////////////////////////////////////////////
00033 WinStatsMonitor::
00034 WinStatsMonitor(WinStatsServer *server) : PStatMonitor(server) {
00035   _window = 0;
00036   _menu_bar = 0;
00037   _options_menu = 0;
00038 
00039   // These will be filled in later when the menu is created.
00040   _time_units = 0;
00041   _scroll_speed = 0.0;
00042   _pause = false;
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: WinStatsMonitor::Destructor
00047 //       Access: Public, Virtual
00048 //  Description:
00049 ////////////////////////////////////////////////////////////////////
00050 WinStatsMonitor::
00051 ~WinStatsMonitor() {
00052   Graphs::iterator gi;
00053   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00054     delete (*gi);
00055   }
00056   _graphs.clear();
00057 
00058   ChartMenus::iterator mi;
00059   for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
00060     delete (*mi);
00061   }
00062   _chart_menus.clear();
00063 
00064   if (_window) {
00065     DestroyWindow(_window);
00066     _window = 0;
00067   }
00068 
00069 #ifdef DEVELOP_WINSTATS
00070   // For Winstats developers, exit when the first monitor closes.
00071   exit(0);
00072 #endif
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: WinStatsMonitor::get_monitor_name
00077 //       Access: Public, Virtual
00078 //  Description: Should be redefined to return a descriptive name for
00079 //               the type of PStatsMonitor this is.
00080 ////////////////////////////////////////////////////////////////////
00081 string WinStatsMonitor::
00082 get_monitor_name() {
00083   return "WinStats";
00084 }
00085 
00086 ////////////////////////////////////////////////////////////////////
00087 //     Function: WinStatsMonitor::initialized
00088 //       Access: Public, Virtual
00089 //  Description: Called after the monitor has been fully set up.  At
00090 //               this time, it will have a valid _client_data pointer,
00091 //               and things like is_alive() and close() will be
00092 //               meaningful.  However, we may not yet know who we're
00093 //               connected to (is_client_known() may return false),
00094 //               and we may not know anything about the threads or
00095 //               collectors we're about to get data on.
00096 ////////////////////////////////////////////////////////////////////
00097 void WinStatsMonitor::
00098 initialized() {
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: WinStatsMonitor::got_hello
00103 //       Access: Public, Virtual
00104 //  Description: Called when the "hello" message has been received
00105 //               from the client.  At this time, the client's hostname
00106 //               and program name will be known.
00107 ////////////////////////////////////////////////////////////////////
00108 void WinStatsMonitor::
00109 got_hello() {
00110   create_window();
00111   open_strip_chart(0, 0, false);
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: WinStatsMonitor::got_bad_version
00116 //       Access: Public, Virtual
00117 //  Description: Like got_hello(), this is called when the "hello"
00118 //               message has been received from the client.  At this
00119 //               time, the client's hostname and program name will be
00120 //               known.  However, the client appears to be an
00121 //               incompatible version and the connection will be
00122 //               terminated; the monitor should issue a message to
00123 //               that effect.
00124 ////////////////////////////////////////////////////////////////////
00125 void WinStatsMonitor::
00126 got_bad_version(int client_major, int client_minor,
00127                 int server_major, int server_minor) {
00128   ostringstream str;
00129   str << "Unable to honor connection attempt from " 
00130       << get_client_progname() << " on " << get_client_hostname() 
00131       << ": unsupported PStats version " 
00132       << client_major << "." << client_minor;
00133 
00134   if (server_minor == 0) {
00135     str << " (server understands version " << server_major
00136         << "." << server_minor << " only).";
00137   } else {
00138     str << " (server understands versions " << server_major
00139         << ".0 through " << server_major << "." << server_minor << ").";
00140   }
00141     
00142   string message = str.str();
00143   MessageBox(NULL, message.c_str(), "Bad version", 
00144              MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: WinStatsMonitor::new_collector
00149 //       Access: Public, Virtual
00150 //  Description: Called whenever a new Collector definition is
00151 //               received from the client.  Generally, the client will
00152 //               send all of its collectors over shortly after
00153 //               connecting, but there's no guarantee that they will
00154 //               all be received before the first frames are received.
00155 //               The monitor should be prepared to accept new Collector
00156 //               definitions midstream.
00157 ////////////////////////////////////////////////////////////////////
00158 void WinStatsMonitor::
00159 new_collector(int collector_index) {
00160   Graphs::iterator gi;
00161   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00162     WinStatsGraph *graph = (*gi);
00163     graph->new_collector(collector_index);
00164   }
00165 
00166   // We might need to update our menus.
00167   ChartMenus::iterator mi;
00168   for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
00169     (*mi)->do_update();
00170   }
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: WinStatsMonitor::new_thread
00175 //       Access: Public, Virtual
00176 //  Description: Called whenever a new Thread definition is
00177 //               received from the client.  Generally, the client will
00178 //               send all of its threads over shortly after
00179 //               connecting, but there's no guarantee that they will
00180 //               all be received before the first frames are received.
00181 //               The monitor should be prepared to accept new Thread
00182 //               definitions midstream.
00183 ////////////////////////////////////////////////////////////////////
00184 void WinStatsMonitor::
00185 new_thread(int thread_index) {
00186   WinStatsChartMenu *chart_menu = new WinStatsChartMenu(this, thread_index);
00187   chart_menu->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
00188   _chart_menus.push_back(chart_menu);
00189   DrawMenuBar(_window);
00190 }
00191 
00192 ////////////////////////////////////////////////////////////////////
00193 //     Function: WinStatsMonitor::new_data
00194 //       Access: Public, Virtual
00195 //  Description: Called as each frame's data is made available.  There
00196 //               is no guarantee the frames will arrive in order, or
00197 //               that all of them will arrive at all.  The monitor
00198 //               should be prepared to accept frames received
00199 //               out-of-order or missing.
00200 ////////////////////////////////////////////////////////////////////
00201 void WinStatsMonitor::
00202 new_data(int thread_index, int frame_number) {
00203   Graphs::iterator gi;
00204   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00205     WinStatsGraph *graph = (*gi);
00206     graph->new_data(thread_index, frame_number);
00207   }
00208 }
00209 
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: WinStatsMonitor::lost_connection
00213 //       Access: Public, Virtual
00214 //  Description: Called whenever the connection to the client has been
00215 //               lost.  This is a permanent state change.  The monitor
00216 //               should update its display to represent this, and may
00217 //               choose to close down automatically.
00218 ////////////////////////////////////////////////////////////////////
00219 void WinStatsMonitor::
00220 lost_connection() {
00221   nout << "Lost connection to " << get_client_hostname() << "\n";
00222 
00223   if (_window) {
00224     DestroyWindow(_window);
00225     _window = 0;
00226   }
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: WinStatsMonitor::idle
00231 //       Access: Public, Virtual
00232 //  Description: If has_idle() returns true, this will be called
00233 //               periodically to allow the monitor to update its
00234 //               display or whatever it needs to do.
00235 ////////////////////////////////////////////////////////////////////
00236 void WinStatsMonitor::
00237 idle() {
00238   // Check if any of our chart menus need updating.
00239   ChartMenus::iterator mi;
00240   for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
00241     (*mi)->check_update();
00242   }
00243 
00244   // Update the frame rate label from the main thread (thread 0).
00245   const PStatThreadData *thread_data = get_client_data()->get_thread_data(0);
00246   double frame_rate = thread_data->get_frame_rate();
00247   if (frame_rate != 0.0f) {
00248     char buffer[128];
00249     sprintf(buffer, "%0.1f ms / %0.1f Hz", 1000.0f / frame_rate, frame_rate);
00250   
00251     MENUITEMINFO mii;
00252     memset(&mii, 0, sizeof(mii));
00253     mii.cbSize = sizeof(mii);
00254     mii.fMask = MIIM_STRING;
00255     mii.dwTypeData = buffer;
00256     SetMenuItemInfo(_menu_bar, MI_frame_rate_label, FALSE, &mii);
00257     DrawMenuBar(_window);
00258   }
00259 }
00260 
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: WinStatsMonitor::has_idle
00263 //       Access: Public, Virtual
00264 //  Description: Should be redefined to return true if you want to
00265 //               redefine idle() and expect it to be called.
00266 ////////////////////////////////////////////////////////////////////
00267 bool WinStatsMonitor::
00268 has_idle() {
00269   return true;
00270 }
00271 
00272 ////////////////////////////////////////////////////////////////////
00273 //     Function: WinStatsMonitor::user_guide_bars_changed
00274 //       Access: Public, Virtual
00275 //  Description: Called when the user guide bars have been changed.
00276 ////////////////////////////////////////////////////////////////////
00277 void WinStatsMonitor::
00278 user_guide_bars_changed() {
00279   Graphs::iterator gi;
00280   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00281     WinStatsGraph *graph = (*gi);
00282     graph->user_guide_bars_changed();
00283   }
00284 }
00285 
00286 ////////////////////////////////////////////////////////////////////
00287 //     Function: WinStatsMonitor::get_window
00288 //       Access: Public
00289 //  Description: Returns the window handle to the monitor's window.
00290 ////////////////////////////////////////////////////////////////////
00291 HWND WinStatsMonitor::
00292 get_window() const {
00293   return _window;
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: WinStatsMonitor::open_strip_chart
00298 //       Access: Public
00299 //  Description: Opens a new strip chart showing the indicated data.
00300 ////////////////////////////////////////////////////////////////////
00301 void WinStatsMonitor::
00302 open_strip_chart(int thread_index, int collector_index, bool show_level) {
00303   WinStatsStripChart *graph = 
00304     new WinStatsStripChart(this, thread_index, collector_index, show_level);
00305   add_graph(graph);
00306 
00307   graph->set_time_units(_time_units);
00308   graph->set_scroll_speed(_scroll_speed);
00309   graph->set_pause(_pause);
00310 }
00311 
00312 ////////////////////////////////////////////////////////////////////
00313 //     Function: WinStatsMonitor::open_piano_roll
00314 //       Access: Public
00315 //  Description: Opens a new piano roll showing the indicated data.
00316 ////////////////////////////////////////////////////////////////////
00317 void WinStatsMonitor::
00318 open_piano_roll(int thread_index) {
00319   WinStatsPianoRoll *graph = new WinStatsPianoRoll(this, thread_index);
00320   add_graph(graph);
00321 
00322   graph->set_time_units(_time_units);
00323   graph->set_scroll_speed(_scroll_speed);
00324   graph->set_pause(_pause);
00325 }
00326 
00327 ////////////////////////////////////////////////////////////////////
00328 //     Function: WinStatsMonitor::lookup_menu
00329 //       Access: Public
00330 //  Description: Returns the MenuDef properties associated with the
00331 //               indicated menu ID.  This specifies what we expect to
00332 //               do when the given menu has been selected.
00333 ////////////////////////////////////////////////////////////////////
00334 const WinStatsMonitor::MenuDef &WinStatsMonitor::
00335 lookup_menu(int menu_id) const {
00336   static MenuDef invalid(0, 0, false);
00337   int menu_index = menu_id - MI_new_chart;
00338   nassertr(menu_index >= 0 && menu_index < (int)_menu_by_id.size(), invalid);
00339   return _menu_by_id[menu_index];
00340 }
00341 
00342 ////////////////////////////////////////////////////////////////////
00343 //     Function: WinStatsMonitor::get_menu_id
00344 //       Access: Public
00345 //  Description: Returns the menu ID that is reserved for the
00346 //               indicated MenuDef properties.  If this is the first
00347 //               time these particular properties have been requested,
00348 //               a new menu ID is returned; otherwise, the existing
00349 //               menu ID is returned.
00350 ////////////////////////////////////////////////////////////////////
00351 int WinStatsMonitor::
00352 get_menu_id(const MenuDef &menu_def) {
00353   MenuByDef::iterator mi;
00354   mi = _menu_by_def.find(menu_def);
00355   if (mi != _menu_by_def.end()) {
00356     return (*mi).second;
00357   }
00358 
00359   // Slot a new id.
00360   int menu_id = (int)_menu_by_id.size() + MI_new_chart;
00361   _menu_by_id.push_back(menu_def);
00362   _menu_by_def[menu_def] = menu_id;
00363 
00364   return menu_id;
00365 }
00366 
00367 ////////////////////////////////////////////////////////////////////
00368 //     Function: WinStatsMonitor::set_time_units
00369 //       Access: Public
00370 //  Description: Called when the user selects a new time units from
00371 //               the monitor pulldown menu, this should adjust the
00372 //               units for all graphs to the indicated mask if it is a
00373 //               time-based graph.
00374 ////////////////////////////////////////////////////////////////////
00375 void WinStatsMonitor::
00376 set_time_units(int unit_mask) {
00377   _time_units = unit_mask;
00378 
00379   // First, change all of the open graphs appropriately.
00380   Graphs::iterator gi;
00381   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00382     WinStatsGraph *graph = (*gi);
00383     graph->set_time_units(_time_units);
00384   }
00385 
00386   // Now change the checkmark on the pulldown menu.
00387   MENUITEMINFO mii;
00388   memset(&mii, 0, sizeof(mii));
00389   mii.cbSize = sizeof(mii);
00390   mii.fMask = MIIM_STATE;
00391 
00392   mii.fState = ((_time_units & PStatGraph::GBU_ms) != 0) ? 
00393     MFS_CHECKED : MFS_UNCHECKED;
00394   SetMenuItemInfo(_options_menu, MI_time_ms, FALSE, &mii);
00395 
00396   mii.fState = ((_time_units & PStatGraph::GBU_hz) != 0) ? 
00397     MFS_CHECKED : MFS_UNCHECKED;
00398   SetMenuItemInfo(_options_menu, MI_time_hz, FALSE, &mii);
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: WinStatsMonitor::set_scroll_speed
00403 //       Access: Public
00404 //  Description: Called when the user selects a new scroll speed from
00405 //               the monitor pulldown menu, this should adjust the
00406 //               speeds for all graphs to the indicated value.
00407 ////////////////////////////////////////////////////////////////////
00408 void WinStatsMonitor::
00409 set_scroll_speed(double scroll_speed) {
00410   _scroll_speed = scroll_speed;
00411 
00412   // First, change all of the open graphs appropriately.
00413   Graphs::iterator gi;
00414   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00415     WinStatsGraph *graph = (*gi);
00416     graph->set_scroll_speed(_scroll_speed);
00417   }
00418 
00419   // Now change the checkmark on the pulldown menu.
00420   MENUITEMINFO mii;
00421   memset(&mii, 0, sizeof(mii));
00422   mii.cbSize = sizeof(mii);
00423   mii.fMask = MIIM_STATE;
00424 
00425   mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 1.0, 0.1) ?
00426     MFS_CHECKED : MFS_UNCHECKED;
00427   SetMenuItemInfo(_speed_menu, MI_speed_1, FALSE, &mii);
00428 
00429   mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 2.0, 0.1) ?
00430     MFS_CHECKED : MFS_UNCHECKED;
00431   SetMenuItemInfo(_speed_menu, MI_speed_2, FALSE, &mii);
00432 
00433   mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 3.0, 0.1) ?
00434     MFS_CHECKED : MFS_UNCHECKED;
00435   SetMenuItemInfo(_speed_menu, MI_speed_3, FALSE, &mii);
00436 
00437   mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 6.0, 0.1) ?
00438     MFS_CHECKED : MFS_UNCHECKED;
00439   SetMenuItemInfo(_speed_menu, MI_speed_6, FALSE, &mii);
00440 
00441   mii.fState = IS_THRESHOLD_EQUAL(_scroll_speed, 12.0, 0.1) ?
00442     MFS_CHECKED : MFS_UNCHECKED;
00443   SetMenuItemInfo(_speed_menu, MI_speed_12, FALSE, &mii);
00444 }
00445 
00446 ////////////////////////////////////////////////////////////////////
00447 //     Function: WinStatsMonitor::set_pause
00448 //       Access: Public
00449 //  Description: Called when the user selects a pause on or pause off
00450 //               option from the menu.
00451 ////////////////////////////////////////////////////////////////////
00452 void WinStatsMonitor::
00453 set_pause(bool pause) {
00454   _pause = pause;
00455 
00456   // First, change all of the open graphs appropriately.
00457   Graphs::iterator gi;
00458   for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) {
00459     WinStatsGraph *graph = (*gi);
00460     graph->set_pause(_pause);
00461   }
00462 
00463   // Now change the checkmark on the pulldown menu.
00464   MENUITEMINFO mii;
00465   memset(&mii, 0, sizeof(mii));
00466   mii.cbSize = sizeof(mii);
00467   mii.fMask = MIIM_STATE;
00468 
00469   mii.fState = _pause ? MFS_CHECKED : MFS_UNCHECKED;
00470   SetMenuItemInfo(_speed_menu, MI_pause, FALSE, &mii);
00471 }
00472 
00473 ////////////////////////////////////////////////////////////////////
00474 //     Function: WinStatsMonitor::add_graph
00475 //       Access: Private
00476 //  Description: Adds the newly-created graph to the list of managed
00477 //               graphs.
00478 ////////////////////////////////////////////////////////////////////
00479 void WinStatsMonitor::
00480 add_graph(WinStatsGraph *graph) {
00481   _graphs.insert(graph);
00482 }
00483 
00484 ////////////////////////////////////////////////////////////////////
00485 //     Function: WinStatsMonitor::remove_graph
00486 //       Access: Private
00487 //  Description: Deletes the indicated graph.
00488 ////////////////////////////////////////////////////////////////////
00489 void WinStatsMonitor::
00490 remove_graph(WinStatsGraph *graph) {
00491   Graphs::iterator gi = _graphs.find(graph);
00492   if (gi != _graphs.end()) {
00493     _graphs.erase(gi);
00494     delete graph;
00495   }
00496 }
00497 
00498 ////////////////////////////////////////////////////////////////////
00499 //     Function: WinStatsMonitor::create_window
00500 //       Access: Private
00501 //  Description: Creates the window for this monitor.
00502 ////////////////////////////////////////////////////////////////////
00503 void WinStatsMonitor::
00504 create_window() {
00505   if (_window) {
00506     return;
00507   }
00508 
00509   HINSTANCE application = GetModuleHandle(NULL);
00510   register_window_class(application);
00511 
00512   _menu_bar = CreateMenu();
00513 
00514   setup_options_menu();
00515   setup_speed_menu();
00516   setup_frame_rate_label();
00517 
00518   ChartMenus::iterator mi;
00519   for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) {
00520     (*mi)->add_to_menu_bar(_menu_bar, MI_frame_rate_label);
00521   }
00522 
00523   _window_title = get_client_progname() + " on " + get_client_hostname();
00524   DWORD window_style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | 
00525     WS_CLIPSIBLINGS | WS_VISIBLE;
00526 
00527   _window = 
00528     CreateWindow(_window_class_name, _window_title.c_str(), window_style,
00529                  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
00530                  NULL, _menu_bar, application, 0);
00531   if (!_window) {
00532     nout << "Could not create monitor window!\n";
00533     exit(1);
00534   }
00535 
00536   SetWindowLongPtr(_window, 0, (LONG_PTR)this);
00537 
00538   // For some reason, SW_SHOWNORMAL doesn't always work, but
00539   // SW_RESTORE seems to.
00540   ShowWindow(_window, SW_RESTORE);
00541   SetForegroundWindow(_window);
00542 }
00543 
00544 ////////////////////////////////////////////////////////////////////
00545 //     Function: WinStatsMonitor::setup_options_menu
00546 //       Access: Private
00547 //  Description: Creates the "Options" pulldown menu.
00548 ////////////////////////////////////////////////////////////////////
00549 void WinStatsMonitor::
00550 setup_options_menu() {
00551   _options_menu = CreatePopupMenu();
00552 
00553   MENUITEMINFO mii;
00554   memset(&mii, 0, sizeof(mii));
00555   mii.cbSize = sizeof(mii);
00556 
00557   mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
00558   mii.fType = MFT_STRING; 
00559   mii.hSubMenu = _options_menu;
00560 
00561   // One day, when there is more than one option here, we will
00562   // actually present this to the user as the "Options" menu.  For
00563   // now, the only option we have is time units.
00564   //mii.dwTypeData = "Options"; 
00565   mii.dwTypeData = "Units"; 
00566   InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
00567 
00568   
00569   mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
00570   mii.fType = MFT_STRING | MFT_RADIOCHECK; 
00571   mii.hbmpChecked = NULL;
00572   mii.hbmpUnchecked = NULL;
00573   mii.fState = MFS_UNCHECKED;
00574   mii.wID = MI_time_ms;
00575   mii.dwTypeData = "ms";
00576   InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii);
00577 
00578   mii.wID = MI_time_hz;
00579   mii.dwTypeData = "Hz";
00580   InsertMenuItem(_options_menu, GetMenuItemCount(_options_menu), TRUE, &mii);
00581 
00582   set_time_units(PStatGraph::GBU_ms);
00583 }
00584 
00585 ////////////////////////////////////////////////////////////////////
00586 //     Function: WinStatsMonitor::setup_speed_menu
00587 //       Access: Private
00588 //  Description: Creates the "Speed" pulldown menu.
00589 ////////////////////////////////////////////////////////////////////
00590 void WinStatsMonitor::
00591 setup_speed_menu() {
00592   _speed_menu = CreatePopupMenu();
00593 
00594   MENUITEMINFO mii;
00595   memset(&mii, 0, sizeof(mii));
00596   mii.cbSize = sizeof(mii);
00597 
00598   mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_SUBMENU;
00599   mii.fType = MFT_STRING; 
00600   mii.hSubMenu = _speed_menu;
00601   mii.dwTypeData = "Speed"; 
00602   InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
00603 
00604   
00605   mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
00606   mii.fType = MFT_STRING | MFT_RADIOCHECK; 
00607   mii.hbmpChecked = NULL;
00608   mii.hbmpUnchecked = NULL;
00609   mii.fState = MFS_UNCHECKED;
00610   mii.wID = MI_speed_1;
00611   mii.dwTypeData = "1";
00612   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00613 
00614   mii.wID = MI_speed_2;
00615   mii.dwTypeData = "2";
00616   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00617 
00618   mii.wID = MI_speed_3;
00619   mii.dwTypeData = "3";
00620   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00621 
00622   mii.wID = MI_speed_6;
00623   mii.dwTypeData = "6";
00624   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00625 
00626   mii.wID = MI_speed_12;
00627   mii.dwTypeData = "12";
00628   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00629 
00630   mii.fMask = MIIM_FTYPE; 
00631   mii.fType = MFT_SEPARATOR; 
00632   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00633 
00634   mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_CHECKMARKS | MIIM_STATE;
00635   mii.fType = MFT_STRING; 
00636   mii.wID = MI_pause;
00637   mii.dwTypeData = "pause";
00638   InsertMenuItem(_speed_menu, GetMenuItemCount(_speed_menu), TRUE, &mii);
00639 
00640   set_scroll_speed(3);
00641   set_pause(false);
00642 }
00643 
00644 ////////////////////////////////////////////////////////////////////
00645 //     Function: WinStatsMonitor::setup_frame_rate_label
00646 //       Access: Private
00647 //  Description: Creates the frame rate label on the right end of the
00648 //               menu bar.  This is used as a text label to display
00649 //               the main thread's frame rate to the user, although it
00650 //               is implemented as a right-justified toplevel menu
00651 //               item that doesn't open to anything.
00652 ////////////////////////////////////////////////////////////////////
00653 void WinStatsMonitor::
00654 setup_frame_rate_label() {
00655   MENUITEMINFO mii;
00656   memset(&mii, 0, sizeof(mii));
00657   mii.cbSize = sizeof(mii);
00658 
00659   mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID;
00660   mii.fType = MFT_STRING | MFT_RIGHTJUSTIFY; 
00661   mii.wID = MI_frame_rate_label;
00662   mii.dwTypeData = ""; 
00663   InsertMenuItem(_menu_bar, GetMenuItemCount(_menu_bar), TRUE, &mii);
00664 }
00665 
00666 ////////////////////////////////////////////////////////////////////
00667 //     Function: WinStatsMonitor::register_window_class
00668 //       Access: Private, Static
00669 //  Description: Registers the window class for the monitor window, if
00670 //               it has not already been registered.
00671 ////////////////////////////////////////////////////////////////////
00672 void WinStatsMonitor::
00673 register_window_class(HINSTANCE application) {
00674   if (_window_class_registered) {
00675     return;
00676   }
00677 
00678   WNDCLASS wc;
00679 
00680   ZeroMemory(&wc, sizeof(WNDCLASS));
00681   wc.style = 0;
00682   wc.lpfnWndProc = (WNDPROC)static_window_proc;
00683   wc.hInstance = application;
00684   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
00685   wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
00686   wc.lpszMenuName = NULL;
00687   wc.lpszClassName = _window_class_name;
00688 
00689   // Reserve space to associate the this pointer with the window.
00690   wc.cbWndExtra = sizeof(WinStatsMonitor *);
00691   
00692   if (!RegisterClass(&wc)) {
00693     nout << "Could not register monitor window class!\n";
00694     exit(1);
00695   }
00696 
00697   _window_class_registered = true;
00698 }
00699 
00700 ////////////////////////////////////////////////////////////////////
00701 //     Function: WinStatsMonitor::static_window_proc
00702 //       Access: Private, Static
00703 //  Description: 
00704 ////////////////////////////////////////////////////////////////////
00705 LONG WINAPI WinStatsMonitor::
00706 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00707   WinStatsMonitor *self = (WinStatsMonitor *)GetWindowLongPtr(hwnd, 0);
00708   if (self != (WinStatsMonitor *)NULL && self->_window == hwnd) {
00709     return self->window_proc(hwnd, msg, wparam, lparam);
00710   } else {
00711     return DefWindowProc(hwnd, msg, wparam, lparam);
00712   }
00713 }
00714 
00715 ////////////////////////////////////////////////////////////////////
00716 //     Function: WinStatsMonitor::window_proc
00717 //       Access: Private
00718 //  Description: 
00719 ////////////////////////////////////////////////////////////////////
00720 LONG WinStatsMonitor::
00721 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00722   switch (msg) {
00723   case WM_DESTROY:
00724     close();
00725     break;
00726 
00727   case WM_COMMAND:
00728     if (HIWORD(wparam) <= 1) {
00729       int menu_id = LOWORD(wparam);
00730       handle_menu_command(menu_id);
00731       return 0;
00732     }
00733     break;
00734 
00735   default:
00736     break;
00737   }
00738 
00739   return DefWindowProc(hwnd, msg, wparam, lparam);
00740 }
00741 
00742 ////////////////////////////////////////////////////////////////////
00743 //     Function: WinStatsMonitor::handle_menu_command
00744 //       Access: Private
00745 //  Description: 
00746 ////////////////////////////////////////////////////////////////////
00747 void WinStatsMonitor::
00748 handle_menu_command(int menu_id) {
00749   switch (menu_id) {
00750   case MI_none:
00751     break;
00752 
00753   case MI_time_ms:
00754     set_time_units(PStatGraph::GBU_ms);
00755     break;
00756 
00757   case MI_time_hz:
00758     set_time_units(PStatGraph::GBU_hz);
00759     break;
00760 
00761   case MI_speed_1:
00762     set_scroll_speed(1);
00763     break;
00764 
00765   case MI_speed_2:
00766     set_scroll_speed(2);
00767     break;
00768 
00769   case MI_speed_3:
00770     set_scroll_speed(3);
00771     break;
00772 
00773   case MI_speed_6:
00774     set_scroll_speed(6);
00775     break;
00776 
00777   case MI_speed_12:
00778     set_scroll_speed(12);
00779     break;
00780 
00781   case MI_pause:
00782     set_pause(!_pause);
00783     break;
00784 
00785   default:
00786     if (menu_id >= MI_new_chart) {
00787       const MenuDef &menu_def = lookup_menu(menu_id);
00788       if (menu_def._collector_index < 0) {
00789         open_piano_roll(menu_def._thread_index);
00790       } else {
00791         open_strip_chart(menu_def._thread_index, menu_def._collector_index,
00792                          menu_def._show_level);
00793       }
00794     }
00795   }
00796 }
 All Classes Functions Variables Enumerations