Panda3D
|
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 }