Panda3D
|
00001 // Filename: gtkStatsMonitor.cxx 00002 // Created by: drose (16Jan06) 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 "gtkStatsMonitor.h" 00016 #include "gtkStats.h" 00017 #include "gtkStatsServer.h" 00018 #include "gtkStatsStripChart.h" 00019 #include "gtkStatsChartMenu.h" 00020 #include "gtkStatsPianoRoll.h" 00021 #include "gtkStatsMenuId.h" 00022 #include "pStatGraph.h" 00023 #include "pStatCollectorDef.h" 00024 #include "indent.h" 00025 00026 typedef void vc(); 00027 00028 GtkItemFactoryEntry GtkStatsMonitor::menu_entries[] = { 00029 { "/Options", NULL, NULL, 0, "<Branch>" }, 00030 { "/Options/Units", NULL, NULL, 0, "<Branch>" }, 00031 { "/Options/Units/ms", NULL, (vc *)&handle_menu_command, MI_time_ms, "<RadioItem>" }, 00032 { "/Options/Units/Hz", NULL, (vc *)&handle_menu_command, MI_time_hz, "/Options/Units/ms" }, 00033 { "/Speed", NULL, NULL, 0, "<Branch>" }, 00034 { "/Speed/1", NULL, (vc *)&handle_menu_command, MI_speed_1, "<RadioItem>" }, 00035 { "/Speed/2", NULL, (vc *)&handle_menu_command, MI_speed_2, "/Speed/1" }, 00036 { "/Speed/3", NULL, (vc *)&handle_menu_command, MI_speed_3, "/Speed/1" }, 00037 { "/Speed/6", NULL, (vc *)&handle_menu_command, MI_speed_6, "/Speed/1" }, 00038 { "/Speed/12", NULL, (vc *)&handle_menu_command, MI_speed_12, "/Speed/1" }, 00039 { "/Speed/sep", NULL, NULL, 0, "<Separator>" }, 00040 { "/Speed/pause", NULL, (vc *)&handle_menu_command, MI_pause, "<CheckItem>" }, 00041 }; 00042 int GtkStatsMonitor::num_menu_entries = sizeof(menu_entries) / sizeof(GtkItemFactoryEntry); 00043 00044 00045 //////////////////////////////////////////////////////////////////// 00046 // Function: GtkStatsMonitor::Constructor 00047 // Access: Public 00048 // Description: 00049 //////////////////////////////////////////////////////////////////// 00050 GtkStatsMonitor:: 00051 GtkStatsMonitor(GtkStatsServer *server) : PStatMonitor(server) { 00052 _window = NULL; 00053 _item_factory = NULL; 00054 00055 // These will be filled in later when the menu is created. 00056 _time_units = 0; 00057 _scroll_speed = 0.0; 00058 _pause = false; 00059 } 00060 00061 //////////////////////////////////////////////////////////////////// 00062 // Function: GtkStatsMonitor::Destructor 00063 // Access: Public, Virtual 00064 // Description: 00065 //////////////////////////////////////////////////////////////////// 00066 GtkStatsMonitor:: 00067 ~GtkStatsMonitor() { 00068 shutdown(); 00069 } 00070 00071 //////////////////////////////////////////////////////////////////// 00072 // Function: GtkStatsMonitor::get_monitor_name 00073 // Access: Public, Virtual 00074 // Description: Should be redefined to return a descriptive name for 00075 // the type of PStatsMonitor this is. 00076 //////////////////////////////////////////////////////////////////// 00077 string GtkStatsMonitor:: 00078 get_monitor_name() { 00079 return "GtkStats"; 00080 } 00081 00082 //////////////////////////////////////////////////////////////////// 00083 // Function: GtkStatsMonitor::initialized 00084 // Access: Public, Virtual 00085 // Description: Called after the monitor has been fully set up. At 00086 // this time, it will have a valid _client_data pointer, 00087 // and things like is_alive() and close() will be 00088 // meaningful. However, we may not yet know who we're 00089 // connected to (is_client_known() may return false), 00090 // and we may not know anything about the threads or 00091 // collectors we're about to get data on. 00092 //////////////////////////////////////////////////////////////////// 00093 void GtkStatsMonitor:: 00094 initialized() { 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 // Function: GtkStatsMonitor::got_hello 00099 // Access: Public, Virtual 00100 // Description: Called when the "hello" message has been received 00101 // from the client. At this time, the client's hostname 00102 // and program name will be known. 00103 //////////////////////////////////////////////////////////////////// 00104 void GtkStatsMonitor:: 00105 got_hello() { 00106 create_window(); 00107 open_strip_chart(0, 0, false); 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: GtkStatsMonitor::got_bad_version 00112 // Access: Public, Virtual 00113 // Description: Like got_hello(), this is called when the "hello" 00114 // message has been received from the client. At this 00115 // time, the client's hostname and program name will be 00116 // known. However, the client appears to be an 00117 // incompatible version and the connection will be 00118 // terminated; the monitor should issue a message to 00119 // that effect. 00120 //////////////////////////////////////////////////////////////////// 00121 void GtkStatsMonitor:: 00122 got_bad_version(int client_major, int client_minor, 00123 int server_major, int server_minor) { 00124 ostringstream str; 00125 str << "Unable to honor connection attempt from " 00126 << get_client_progname() << " on " << get_client_hostname() 00127 << ": unsupported PStats version " 00128 << client_major << "." << client_minor; 00129 00130 if (server_minor == 0) { 00131 str << " (server understands version " << server_major 00132 << "." << server_minor << " only)."; 00133 } else { 00134 str << " (server understands versions " << server_major 00135 << ".0 through " << server_major << "." << server_minor << ")."; 00136 } 00137 00138 string message = str.str(); 00139 GtkWidget *dialog = 00140 gtk_message_dialog_new(GTK_WINDOW(main_window), 00141 GTK_DIALOG_DESTROY_WITH_PARENT, 00142 GTK_MESSAGE_ERROR, 00143 GTK_BUTTONS_CLOSE, 00144 message.c_str()); 00145 gtk_dialog_run(GTK_DIALOG(dialog)); 00146 gtk_widget_destroy(dialog); 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: GtkStatsMonitor::new_collector 00151 // Access: Public, Virtual 00152 // Description: Called whenever a new Collector definition is 00153 // received from the client. Generally, the client will 00154 // send all of its collectors over shortly after 00155 // connecting, but there's no guarantee that they will 00156 // all be received before the first frames are received. 00157 // The monitor should be prepared to accept new Collector 00158 // definitions midstream. 00159 //////////////////////////////////////////////////////////////////// 00160 void GtkStatsMonitor:: 00161 new_collector(int collector_index) { 00162 Graphs::iterator gi; 00163 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00164 GtkStatsGraph *graph = (*gi); 00165 graph->new_collector(collector_index); 00166 } 00167 00168 // We might need to update our menus. 00169 ChartMenus::iterator mi; 00170 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) { 00171 (*mi)->do_update(); 00172 } 00173 } 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: GtkStatsMonitor::new_thread 00177 // Access: Public, Virtual 00178 // Description: Called whenever a new Thread definition is 00179 // received from the client. Generally, the client will 00180 // send all of its threads over shortly after 00181 // connecting, but there's no guarantee that they will 00182 // all be received before the first frames are received. 00183 // The monitor should be prepared to accept new Thread 00184 // definitions midstream. 00185 //////////////////////////////////////////////////////////////////// 00186 void GtkStatsMonitor:: 00187 new_thread(int thread_index) { 00188 GtkStatsChartMenu *chart_menu = new GtkStatsChartMenu(this, thread_index); 00189 GtkWidget *menu_bar = gtk_item_factory_get_widget(_item_factory, "<PStats>"); 00190 chart_menu->add_to_menu_bar(menu_bar, _next_chart_index); 00191 ++_next_chart_index; 00192 _chart_menus.push_back(chart_menu); 00193 } 00194 00195 //////////////////////////////////////////////////////////////////// 00196 // Function: GtkStatsMonitor::new_data 00197 // Access: Public, Virtual 00198 // Description: Called as each frame's data is made available. There 00199 // is no guarantee the frames will arrive in order, or 00200 // that all of them will arrive at all. The monitor 00201 // should be prepared to accept frames received 00202 // out-of-order or missing. 00203 //////////////////////////////////////////////////////////////////// 00204 void GtkStatsMonitor:: 00205 new_data(int thread_index, int frame_number) { 00206 Graphs::iterator gi; 00207 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00208 GtkStatsGraph *graph = (*gi); 00209 graph->new_data(thread_index, frame_number); 00210 } 00211 } 00212 00213 00214 //////////////////////////////////////////////////////////////////// 00215 // Function: GtkStatsMonitor::lost_connection 00216 // Access: Public, Virtual 00217 // Description: Called whenever the connection to the client has been 00218 // lost. This is a permanent state change. The monitor 00219 // should update its display to represent this, and may 00220 // choose to close down automatically. 00221 //////////////////////////////////////////////////////////////////// 00222 void GtkStatsMonitor:: 00223 lost_connection() { 00224 nout << "Lost connection to " << get_client_hostname() << "\n"; 00225 00226 shutdown(); 00227 } 00228 00229 //////////////////////////////////////////////////////////////////// 00230 // Function: GtkStatsMonitor::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 GtkStatsMonitor:: 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 gtk_label_set_text(GTK_LABEL(_frame_rate_label), buffer); 00252 } 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: GtkStatsMonitor::has_idle 00257 // Access: Public, Virtual 00258 // Description: Should be redefined to return true if you want to 00259 // redefine idle() and expect it to be called. 00260 //////////////////////////////////////////////////////////////////// 00261 bool GtkStatsMonitor:: 00262 has_idle() { 00263 return true; 00264 } 00265 00266 //////////////////////////////////////////////////////////////////// 00267 // Function: GtkStatsMonitor::user_guide_bars_changed 00268 // Access: Public, Virtual 00269 // Description: Called when the user guide bars have been changed. 00270 //////////////////////////////////////////////////////////////////// 00271 void GtkStatsMonitor:: 00272 user_guide_bars_changed() { 00273 Graphs::iterator gi; 00274 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00275 GtkStatsGraph *graph = (*gi); 00276 graph->user_guide_bars_changed(); 00277 } 00278 } 00279 00280 //////////////////////////////////////////////////////////////////// 00281 // Function: GtkStatsMonitor::get_window 00282 // Access: Public 00283 // Description: Returns the window handle to the monitor's window. 00284 //////////////////////////////////////////////////////////////////// 00285 GtkWidget *GtkStatsMonitor:: 00286 get_window() const { 00287 return _window; 00288 } 00289 00290 //////////////////////////////////////////////////////////////////// 00291 // Function: GtkStatsMonitor::open_strip_chart 00292 // Access: Public 00293 // Description: Opens a new strip chart showing the indicated data. 00294 //////////////////////////////////////////////////////////////////// 00295 void GtkStatsMonitor:: 00296 open_strip_chart(int thread_index, int collector_index, bool show_level) { 00297 GtkStatsStripChart *graph = 00298 new GtkStatsStripChart(this, thread_index, collector_index, show_level); 00299 add_graph(graph); 00300 00301 graph->set_time_units(_time_units); 00302 graph->set_scroll_speed(_scroll_speed); 00303 graph->set_pause(_pause); 00304 } 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: GtkStatsMonitor::open_piano_roll 00308 // Access: Public 00309 // Description: Opens a new piano roll showing the indicated data. 00310 //////////////////////////////////////////////////////////////////// 00311 void GtkStatsMonitor:: 00312 open_piano_roll(int thread_index) { 00313 GtkStatsPianoRoll *graph = new GtkStatsPianoRoll(this, thread_index); 00314 add_graph(graph); 00315 00316 graph->set_time_units(_time_units); 00317 graph->set_scroll_speed(_scroll_speed); 00318 graph->set_pause(_pause); 00319 } 00320 00321 //////////////////////////////////////////////////////////////////// 00322 // Function: GtkStatsMonitor::add_menu 00323 // Access: Public 00324 // Description: Adds a new MenuDef to the monitor, or returns an 00325 // existing one if there is already one just like it. 00326 //////////////////////////////////////////////////////////////////// 00327 const GtkStatsMonitor::MenuDef *GtkStatsMonitor:: 00328 add_menu(const MenuDef &menu_def) { 00329 pair<Menus::iterator, bool> result = _menus.insert(menu_def); 00330 Menus::iterator mi = result.first; 00331 const GtkStatsMonitor::MenuDef &new_menu_def = (*mi); 00332 if (result.second) { 00333 // A new MenuDef was inserted. 00334 ((GtkStatsMonitor::MenuDef &)new_menu_def)._monitor = this; 00335 } 00336 return &new_menu_def; 00337 } 00338 00339 //////////////////////////////////////////////////////////////////// 00340 // Function: GtkStatsMonitor::set_time_units 00341 // Access: Public 00342 // Description: Called when the user selects a new time units from 00343 // the monitor pulldown menu, this should adjust the 00344 // units for all graphs to the indicated mask if it is a 00345 // time-based graph. 00346 //////////////////////////////////////////////////////////////////// 00347 void GtkStatsMonitor:: 00348 set_time_units(int unit_mask) { 00349 _time_units = unit_mask; 00350 00351 // First, change all of the open graphs appropriately. 00352 Graphs::iterator gi; 00353 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00354 GtkStatsGraph *graph = (*gi); 00355 graph->set_time_units(_time_units); 00356 } 00357 } 00358 00359 //////////////////////////////////////////////////////////////////// 00360 // Function: GtkStatsMonitor::set_scroll_speed 00361 // Access: Public 00362 // Description: Called when the user selects a new scroll speed from 00363 // the monitor pulldown menu, this should adjust the 00364 // speeds for all graphs to the indicated value. 00365 //////////////////////////////////////////////////////////////////// 00366 void GtkStatsMonitor:: 00367 set_scroll_speed(double scroll_speed) { 00368 _scroll_speed = scroll_speed; 00369 00370 // First, change all of the open graphs appropriately. 00371 Graphs::iterator gi; 00372 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00373 GtkStatsGraph *graph = (*gi); 00374 graph->set_scroll_speed(_scroll_speed); 00375 } 00376 } 00377 00378 //////////////////////////////////////////////////////////////////// 00379 // Function: GtkStatsMonitor::set_pause 00380 // Access: Public 00381 // Description: Called when the user selects a pause on or pause off 00382 // option from the menu. 00383 //////////////////////////////////////////////////////////////////// 00384 void GtkStatsMonitor:: 00385 set_pause(bool pause) { 00386 _pause = pause; 00387 00388 // First, change all of the open graphs appropriately. 00389 Graphs::iterator gi; 00390 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00391 GtkStatsGraph *graph = (*gi); 00392 graph->set_pause(_pause); 00393 } 00394 } 00395 00396 //////////////////////////////////////////////////////////////////// 00397 // Function: GtkStatsMonitor::add_graph 00398 // Access: Private 00399 // Description: Adds the newly-created graph to the list of managed 00400 // graphs. 00401 //////////////////////////////////////////////////////////////////// 00402 void GtkStatsMonitor:: 00403 add_graph(GtkStatsGraph *graph) { 00404 _graphs.insert(graph); 00405 } 00406 00407 //////////////////////////////////////////////////////////////////// 00408 // Function: GtkStatsMonitor::remove_graph 00409 // Access: Private 00410 // Description: Deletes the indicated graph. 00411 //////////////////////////////////////////////////////////////////// 00412 void GtkStatsMonitor:: 00413 remove_graph(GtkStatsGraph *graph) { 00414 Graphs::iterator gi = _graphs.find(graph); 00415 if (gi != _graphs.end()) { 00416 _graphs.erase(gi); 00417 delete graph; 00418 } 00419 } 00420 00421 //////////////////////////////////////////////////////////////////// 00422 // Function: GtkStatsMonitor::create_window 00423 // Access: Private 00424 // Description: Creates the window for this monitor. 00425 //////////////////////////////////////////////////////////////////// 00426 void GtkStatsMonitor:: 00427 create_window() { 00428 if (_window != NULL) { 00429 return; 00430 } 00431 00432 _window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 00433 00434 g_signal_connect(G_OBJECT(_window), "delete_event", 00435 G_CALLBACK(window_delete_event), this); 00436 g_signal_connect(G_OBJECT(_window), "destroy", 00437 G_CALLBACK(window_destroy), this); 00438 00439 _window_title = get_client_progname() + " on " + get_client_hostname(); 00440 gtk_window_set_title(GTK_WINDOW(_window), _window_title.c_str()); 00441 00442 gtk_window_set_default_size(GTK_WINDOW(_window), 500, 360); 00443 00444 // Set up the menu. 00445 GtkAccelGroup *accel_group = gtk_accel_group_new(); 00446 _item_factory = 00447 gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<PStats>", accel_group); 00448 gtk_item_factory_create_items(_item_factory, num_menu_entries, menu_entries, 00449 this); 00450 gtk_window_add_accel_group(GTK_WINDOW(_window), accel_group); 00451 GtkWidget *menu_bar = gtk_item_factory_get_widget(_item_factory, "<PStats>"); 00452 _next_chart_index = 2; 00453 00454 setup_frame_rate_label(); 00455 00456 ChartMenus::iterator mi; 00457 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) { 00458 (*mi)->add_to_menu_bar(menu_bar, _next_chart_index); 00459 ++_next_chart_index; 00460 } 00461 00462 // Pack the menu into the window. 00463 GtkWidget *main_vbox = gtk_vbox_new(FALSE, 1); 00464 gtk_container_add(GTK_CONTAINER(_window), main_vbox); 00465 gtk_box_pack_start(GTK_BOX(main_vbox), menu_bar, FALSE, TRUE, 0); 00466 00467 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item(_item_factory, "/Speed/3")), 00468 TRUE); 00469 set_scroll_speed(3); 00470 00471 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item(_item_factory, "/Options/Units/ms")), 00472 TRUE); 00473 set_time_units(PStatGraph::GBU_ms); 00474 00475 gtk_widget_show_all(_window); 00476 gtk_widget_show(_window); 00477 00478 set_pause(false); 00479 } 00480 00481 //////////////////////////////////////////////////////////////////// 00482 // Function: GtkStatsMonitor::shutdown 00483 // Access: Private 00484 // Description: Closes all the graphs associated with this monitor. 00485 //////////////////////////////////////////////////////////////////// 00486 void GtkStatsMonitor:: 00487 shutdown() { 00488 Graphs::iterator gi; 00489 for (gi = _graphs.begin(); gi != _graphs.end(); ++gi) { 00490 delete (*gi); 00491 } 00492 _graphs.clear(); 00493 00494 ChartMenus::iterator mi; 00495 for (mi = _chart_menus.begin(); mi != _chart_menus.end(); ++mi) { 00496 delete (*mi); 00497 } 00498 _chart_menus.clear(); 00499 00500 if (_window != NULL) { 00501 gtk_widget_destroy(_window); 00502 _window = NULL; 00503 } 00504 00505 #ifdef DEVELOP_GTKSTATS 00506 // For GtkStats developers, exit when the first monitor closes. 00507 gtk_main_quit(); 00508 #endif 00509 } 00510 00511 //////////////////////////////////////////////////////////////////// 00512 // Function: GtkStatsMonitor::window_delete_event 00513 // Access: Private, Static 00514 // Description: Callback when the window is closed by the user. 00515 //////////////////////////////////////////////////////////////////// 00516 gboolean GtkStatsMonitor:: 00517 window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { 00518 // Returning FALSE to indicate we should destroy the window 00519 // when the user selects "close". 00520 return FALSE; 00521 } 00522 00523 //////////////////////////////////////////////////////////////////// 00524 // Function: GtkStatsMonitor::window_destroy 00525 // Access: Private, Static 00526 // Description: Callback when the window is destroyed by the system 00527 // (or by delete_event). 00528 //////////////////////////////////////////////////////////////////// 00529 void GtkStatsMonitor:: 00530 window_destroy(GtkWidget *widget, gpointer data) { 00531 GtkStatsMonitor *self = (GtkStatsMonitor *)data; 00532 self->close(); 00533 } 00534 00535 //////////////////////////////////////////////////////////////////// 00536 // Function: GtkStatsMonitor::setup_frame_rate_label 00537 // Access: Private 00538 // Description: Creates the frame rate label on the right end of the 00539 // menu bar. This is used as a text label to display 00540 // the main thread's frame rate to the user, although it 00541 // is implemented as a right-justified toplevel menu 00542 // item that doesn't open to anything. 00543 //////////////////////////////////////////////////////////////////// 00544 void GtkStatsMonitor:: 00545 setup_frame_rate_label() { 00546 GtkWidget *menu_bar = gtk_item_factory_get_widget(_item_factory, "<PStats>"); 00547 00548 _frame_rate_menu_item = gtk_menu_item_new(); 00549 _frame_rate_label = gtk_label_new(""); 00550 gtk_container_add(GTK_CONTAINER(_frame_rate_menu_item), _frame_rate_label); 00551 00552 gtk_widget_show(_frame_rate_menu_item); 00553 gtk_widget_show(_frame_rate_label); 00554 gtk_menu_item_right_justify(GTK_MENU_ITEM(_frame_rate_menu_item)); 00555 00556 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), _frame_rate_menu_item); 00557 } 00558 00559 //////////////////////////////////////////////////////////////////// 00560 // Function: GtkStatsMonitor::handle_menu_command 00561 // Access: Private, Static 00562 // Description: 00563 //////////////////////////////////////////////////////////////////// 00564 void GtkStatsMonitor:: 00565 handle_menu_command(gpointer callback_data, guint menu_id, GtkWidget *widget) { 00566 GtkStatsMonitor *self = (GtkStatsMonitor *)callback_data; 00567 switch (menu_id) { 00568 case MI_none: 00569 break; 00570 00571 case MI_time_ms: 00572 self->set_time_units(PStatGraph::GBU_ms); 00573 break; 00574 00575 case MI_time_hz: 00576 self->set_time_units(PStatGraph::GBU_hz); 00577 break; 00578 00579 case MI_speed_1: 00580 self->set_scroll_speed(1); 00581 break; 00582 00583 case MI_speed_2: 00584 self->set_scroll_speed(2); 00585 break; 00586 00587 case MI_speed_3: 00588 self->set_scroll_speed(3); 00589 break; 00590 00591 case MI_speed_6: 00592 self->set_scroll_speed(6); 00593 break; 00594 00595 case MI_speed_12: 00596 self->set_scroll_speed(12); 00597 break; 00598 00599 case MI_pause: 00600 self->set_pause(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))); 00601 break; 00602 } 00603 }