Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 1 | /* |
| 2 | *------------------------------------------------------------------ |
| 3 | * Copyright (c) 2006-2016 Cisco and/or its affiliates. |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at: |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <stdio.h> |
| 18 | #include <gtk/gtk.h> |
| 19 | #define GTK_ENABLE_BROKEN // DGMS |
| 20 | #include <gtk/gtktext.h> |
| 21 | #include <stdlib.h> |
| 22 | #include "g2.h" |
| 23 | #include <string.h> |
| 24 | |
| 25 | /* |
| 26 | * locals |
| 27 | */ |
| 28 | static GtkWidget *s_mainmenubar; |
| 29 | static GtkWidget *s_filemenu; |
| 30 | static GtkWidget *s_readdefs; |
| 31 | static GtkWidget *s_readevents; |
| 32 | static GtkWidget *s_readeventsclock; |
| 33 | static GtkWidget *s_readcpel; |
| 34 | static GtkWidget *s_readclib; |
| 35 | static GtkWidget *s_print; |
| 36 | static GtkWidget *s_quit; |
| 37 | |
| 38 | static GtkWidget *s_mainfilemenu; |
| 39 | static GtkWidget *s_help_general; |
| 40 | static GtkWidget *s_help_about; |
| 41 | static GtkWidget *s_mainhelpmenu; |
| 42 | static GtkWidget *s_helpmenu; |
| 43 | |
| 44 | static GtkWidget *s_filesel; |
| 45 | static GtkWidget *s_eventsel; |
| 46 | |
| 47 | typedef struct md_ { |
| 48 | GtkWidget *entry; |
| 49 | GtkWidget *label; |
| 50 | GtkWidget *dialog; |
| 51 | boolean (*callback)(char *); |
| 52 | char *retry_text; |
| 53 | } md_t; |
| 54 | |
| 55 | char *general_help = "\n" |
| 56 | "G2 is a performance event visualization tool.\n" |
| 57 | "\n" |
| 58 | "To view CPEL-format event data:\n" |
| 59 | "g2 --cpel <filename>\n" |
| 60 | "or use the File Menu->Read CPEL file option.\n" |
| 61 | "\n" |
| 62 | "To view vppinfra-format (.../open-repo/vppinfra/vppinfra/elog.h) event data:\n" |
| 63 | "g2 --clib <filename>\n" |
| 64 | "or use the File Menu->Read clib file option.\n" |
| 65 | "\n" |
| 66 | "To toggle event detail boxes, left-mouse-click on an event.\n" |
| 67 | "\n" |
| 68 | "To zoom to an area, depress the left mouse button. Move the\n" |
| 69 | "mouse. Release the mouse.\n" |
| 70 | "\n" |
| 71 | "To use the time ruler, depress the right mouse button. Move the\n" |
| 72 | "mouse. Release when done.\n" |
| 73 | "\n" |
| 74 | "To push a track to the bottom, <ctrl><left-mouse>\n" |
| 75 | "\n" |
| 76 | "To pull a track to the top, <shift><left-mouse>\n" |
| 77 | "\n" |
| 78 | "To selectively color/uncolor a track, <ctrl><shift><left-mouse>\n" |
| 79 | "\n" |
| 80 | "To make the mouse scrollwheel faster, press <shift>\n" |
| 81 | "\n" |
| 82 | "Hotkeys, supposedly Quake-like:\n" |
| 83 | " w - zoom-in\n" |
| 84 | " s - zoom-out\n" |
| 85 | " a - pan-left\n" |
| 86 | " d - pan-right\n" |
| 87 | " r - pan-up\n" |
| 88 | " f - pan-down\n" |
| 89 | " t - less traces\n" |
| 90 | " g - more traces\n" |
| 91 | "\n" |
| 92 | " e - toggle summary-mode\n" |
| 93 | " c - toggle color-mode\n" |
| 94 | "\n" |
| 95 | " x - take snapshot\n" |
| 96 | " z - go to next snapshot\n" |
| 97 | " p - put snapshots to snapshots.g2 \n" |
| 98 | " l - load snapshots from snapshots.g2\n" |
| 99 | "\n" |
| 100 | "<ctrl>q - quit\n" |
| 101 | "Send comments / bug reports to the \"fd.io\" mailing list.\n"; |
| 102 | |
| 103 | /**************************************************************************** |
| 104 | * debug_dialog_callback |
| 105 | ****************************************************************************/ |
| 106 | |
| 107 | boolean debug_dialog_callback (char *s) |
| 108 | { |
| 109 | g_print("Dialog result: %s", s); |
| 110 | return (TRUE); |
| 111 | } |
| 112 | |
| 113 | /**************************************************************************** |
| 114 | * get_dialog_value |
| 115 | ****************************************************************************/ |
| 116 | |
| 117 | static void get_dialog_value (GtkWidget *dialog, gpointer user_data) |
| 118 | { |
| 119 | md_t *md = (md_t *)user_data; |
| 120 | char * cb_arg; |
| 121 | |
| 122 | cb_arg = (char *) gtk_entry_get_text(GTK_ENTRY(md->entry)); |
| 123 | |
| 124 | if ((*md->callback)(cb_arg)) { |
| 125 | gtk_grab_remove(md->dialog); |
| 126 | gtk_widget_destroy(md->dialog); |
| 127 | } else { |
| 128 | gtk_label_set_text (GTK_LABEL(md->label), md->retry_text); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | /**************************************************************************** |
| 133 | * modal_dialog |
| 134 | ****************************************************************************/ |
| 135 | |
| 136 | void modal_dialog (char *label_text, char *retry_text, char *default_value, |
| 137 | boolean (*cb)(char *)) |
| 138 | { |
| 139 | GtkWidget *dialog, *label, *ok_button, *entry; |
| 140 | static md_t dlg; |
| 141 | md_t *md = &dlg; |
| 142 | |
| 143 | dialog = gtk_dialog_new(); |
| 144 | label = gtk_label_new(label_text); |
| 145 | |
| 146 | entry = gtk_entry_new(); |
| 147 | if (default_value) |
| 148 | gtk_entry_set_text(GTK_ENTRY(entry), default_value); |
| 149 | |
| 150 | ok_button = gtk_button_new_with_label("OK"); |
| 151 | |
| 152 | md->entry = entry; |
| 153 | md->label = label; |
| 154 | md->retry_text = retry_text; |
| 155 | md->dialog = dialog; |
| 156 | if (cb) |
| 157 | md->callback = cb; |
| 158 | else |
| 159 | md->callback = debug_dialog_callback; |
| 160 | |
| 161 | gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", |
| 162 | GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); |
| 163 | |
| 164 | gtk_signal_connect (GTK_OBJECT (entry), "activate", |
| 165 | GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); |
| 166 | |
| 167 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), |
| 168 | entry); |
| 169 | |
| 170 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), |
| 171 | ok_button); |
| 172 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); |
| 173 | gtk_widget_show_all(dialog); |
| 174 | gtk_widget_grab_focus(entry); |
| 175 | gtk_grab_add(dialog); |
| 176 | } |
| 177 | |
| 178 | /**************************************************************************** |
| 179 | * get_eventdef_name |
| 180 | ****************************************************************************/ |
| 181 | |
| 182 | static void get_eventdef_name (GtkFileSelection *sel, gpointer user_data) |
| 183 | { |
| 184 | char *filename = (char *) gtk_file_selection_get_filename ( |
| 185 | GTK_FILE_SELECTION(s_filesel)); |
| 186 | read_event_definitions(filename); |
| 187 | set_window_title(filename); |
| 188 | } |
| 189 | |
| 190 | /**************************************************************************** |
| 191 | * read_eventdef_callback |
| 192 | ****************************************************************************/ |
| 193 | |
| 194 | static void read_eventdef_callback(GtkToggleButton *item, gpointer data) |
| 195 | { |
| 196 | |
| 197 | s_filesel = gtk_file_selection_new("Read Event Definitions From..."); |
| 198 | |
| 199 | gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), |
| 200 | "../h/elog.h"); |
| 201 | |
| 202 | gtk_signal_connect (GTK_OBJECT ( |
| 203 | GTK_FILE_SELECTION(s_filesel)->ok_button), |
| 204 | "clicked", |
| 205 | GTK_SIGNAL_FUNC(get_eventdef_name), NULL); |
| 206 | |
| 207 | gtk_signal_connect_object (GTK_OBJECT ( |
| 208 | GTK_FILE_SELECTION(s_filesel)->ok_button), |
| 209 | "clicked", |
| 210 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 211 | (gpointer) s_filesel); |
| 212 | |
| 213 | gtk_signal_connect_object (GTK_OBJECT ( |
| 214 | GTK_FILE_SELECTION(s_filesel)->cancel_button), |
| 215 | "clicked", |
| 216 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 217 | (gpointer) s_filesel); |
| 218 | gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); |
| 219 | gtk_widget_show (s_filesel); |
| 220 | } |
| 221 | |
| 222 | /**************************************************************************** |
| 223 | * get_events_name |
| 224 | ****************************************************************************/ |
| 225 | |
| 226 | static void get_events_name (GtkFileSelection *sel, gpointer user_data) |
| 227 | { |
| 228 | char *filename = (char *) gtk_file_selection_get_filename ( |
| 229 | GTK_FILE_SELECTION(s_eventsel)); |
| 230 | read_events(filename); |
| 231 | view1_display_when_idle(); |
| 232 | } |
| 233 | |
| 234 | |
| 235 | /**************************************************************************** |
| 236 | * get_ticks_per_ns |
| 237 | ****************************************************************************/ |
| 238 | |
| 239 | static boolean get_ticks_per_ns (char *value) |
| 240 | { |
| 241 | double rv; |
| 242 | |
| 243 | rv = atof (value); |
| 244 | |
| 245 | if (rv == 0.0 || rv > 100000) |
| 246 | return(FALSE); |
| 247 | |
| 248 | ticks_per_ns = rv; |
| 249 | ticks_per_ns_set = TRUE; |
| 250 | |
| 251 | gtk_widget_show(s_eventsel); |
| 252 | return(TRUE); |
| 253 | } |
| 254 | |
| 255 | /**************************************************************************** |
| 256 | * read_events_callback |
| 257 | ****************************************************************************/ |
| 258 | |
| 259 | static void read_events_callback(GtkToggleButton *item, gpointer data) |
| 260 | { |
| 261 | char tmpbuf [32]; |
| 262 | |
| 263 | s_eventsel = gtk_file_selection_new("Read Events From..."); |
| 264 | |
| 265 | gtk_signal_connect (GTK_OBJECT ( |
| 266 | GTK_FILE_SELECTION(s_eventsel)->ok_button), |
| 267 | "clicked", |
| 268 | GTK_SIGNAL_FUNC(get_events_name), NULL); |
| 269 | |
| 270 | gtk_signal_connect_object (GTK_OBJECT ( |
| 271 | GTK_FILE_SELECTION(s_eventsel)->ok_button), |
| 272 | "clicked", |
| 273 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 274 | (gpointer) s_eventsel); |
| 275 | |
| 276 | gtk_signal_connect_object (GTK_OBJECT ( |
| 277 | GTK_FILE_SELECTION(s_eventsel)->cancel_button), |
| 278 | "clicked", |
| 279 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 280 | (gpointer) s_eventsel); |
| 281 | gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_eventsel)); |
| 282 | |
| 283 | if (ticks_per_ns_set) |
| 284 | gtk_widget_show (s_eventsel); |
| 285 | else { |
| 286 | sprintf(tmpbuf, "%.3f", ticks_per_ns); |
| 287 | modal_dialog ("Please enter clock ticks per nanosecond", |
| 288 | "Invalid: Please enter clock ticks per nanosecond", |
| 289 | tmpbuf, get_ticks_per_ns); |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | /**************************************************************************** |
| 294 | * read_eventclock_callback |
| 295 | ****************************************************************************/ |
| 296 | |
| 297 | static void read_eventsclock_callback(GtkToggleButton *item, gpointer data) |
| 298 | { |
| 299 | ticks_per_ns_set = FALSE; |
| 300 | read_events_callback(item, data); |
| 301 | } |
| 302 | |
| 303 | /**************************************************************************** |
| 304 | * infobox_size_request |
| 305 | ****************************************************************************/ |
| 306 | |
| 307 | void infobox_size_request (GtkWidget *widget, GtkRequisition *req, |
| 308 | gpointer user_data) |
| 309 | { |
| 310 | char *text = (char *)user_data; |
| 311 | char *cp; |
| 312 | int widest_line_in_chars; |
| 313 | int w; |
| 314 | int nlines; |
| 315 | |
| 316 | /* |
| 317 | * You'd think that the string extent function would work here. |
| 318 | * You'd be wrong. |
| 319 | */ |
| 320 | nlines = w = widest_line_in_chars = 0; |
| 321 | for (cp = text; *cp; cp++) { |
| 322 | if (*cp == '\n') { |
| 323 | if (w > widest_line_in_chars) { |
| 324 | widest_line_in_chars = w; |
| 325 | } |
| 326 | w = 0; |
| 327 | nlines++; |
| 328 | } |
| 329 | w++; |
| 330 | } |
| 331 | |
| 332 | nlines++; |
| 333 | |
| 334 | req->width = (widest_line_in_chars * 8) + 20; |
| 335 | req->height = (nlines * 13) + 10; |
| 336 | } |
| 337 | |
| 338 | /**************************************************************************** |
| 339 | * infobox |
| 340 | ****************************************************************************/ |
| 341 | |
| 342 | void infobox(char *label_text, char *text) |
| 343 | { |
| 344 | GtkWidget *dialog, *label, *ok_button, *entry; |
| 345 | GtkWidget *box; |
| 346 | |
| 347 | dialog = gtk_dialog_new(); |
| 348 | label = gtk_label_new(label_text); |
| 349 | |
| 350 | entry = gtk_text_new(NULL, NULL); |
| 351 | |
| 352 | gtk_signal_connect (GTK_OBJECT (entry), "size-request", |
| 353 | GTK_SIGNAL_FUNC(infobox_size_request), |
| 354 | (gpointer) text); |
| 355 | |
| 356 | gtk_text_insert(GTK_TEXT(entry), g_font, &fg_black, &bg_white, |
| 357 | text, -1); |
| 358 | |
| 359 | gtk_text_set_editable(GTK_TEXT(entry), FALSE); |
| 360 | |
| 361 | ok_button = gtk_button_new_with_label("OK"); |
| 362 | |
| 363 | gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked", |
| 364 | GTK_SIGNAL_FUNC(gtk_widget_destroy), |
| 365 | (gpointer) GTK_OBJECT(dialog)); |
| 366 | |
| 367 | box = gtk_vbox_new(FALSE, 5); |
| 368 | |
| 369 | |
| 370 | gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); |
| 371 | gtk_box_pack_start(GTK_BOX(box), ok_button, FALSE, FALSE, 0); |
| 372 | |
| 373 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), |
| 374 | box); |
| 375 | |
| 376 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); |
| 377 | gtk_widget_show_all(dialog); |
| 378 | } |
| 379 | |
| 380 | /**************************************************************************** |
| 381 | * help_general_callback |
| 382 | ****************************************************************************/ |
| 383 | |
| 384 | static void help_general_callback(GtkToggleButton *item, gpointer data) |
| 385 | { |
| 386 | infobox("General Help", general_help); |
| 387 | } |
| 388 | |
| 389 | /**************************************************************************** |
| 390 | * help_about_callback |
| 391 | ****************************************************************************/ |
| 392 | |
| 393 | static void help_about_callback(GtkToggleButton *item, gpointer data) |
| 394 | { |
| 395 | char tmpbuf [1024]; |
| 396 | sprintf (tmpbuf, "G2 -- Graphical Event Viewer\n\n"); |
| 397 | view1_about(tmpbuf); |
| 398 | pointsel_about(tmpbuf); |
| 399 | events_about(tmpbuf); |
| 400 | sprintf (tmpbuf+strlen(tmpbuf), "\n%s\n", version_string); |
| 401 | sprintf (tmpbuf+strlen(tmpbuf), "%s\n", minor_v_string); |
| 402 | infobox("About", tmpbuf); |
| 403 | } |
| 404 | |
| 405 | |
| 406 | /**************************************************************************** |
| 407 | * get_cpel_name |
| 408 | ****************************************************************************/ |
| 409 | |
| 410 | static void get_cpel_name (GtkFileSelection *sel, gpointer user_data) |
| 411 | { |
| 412 | char *filename = (char *)gtk_file_selection_get_filename ( |
| 413 | GTK_FILE_SELECTION(s_filesel)); |
| 414 | read_cpel_file(filename); |
| 415 | set_window_title(filename); |
| 416 | } |
| 417 | |
| 418 | /**************************************************************************** |
| 419 | * get_clib_name |
| 420 | ****************************************************************************/ |
| 421 | |
| 422 | static void get_clib_name (GtkFileSelection *sel, gpointer user_data) |
| 423 | { |
| 424 | char *filename = (char *) gtk_file_selection_get_filename ( |
| 425 | GTK_FILE_SELECTION(s_filesel)); |
| 426 | read_clib_file(filename); |
| 427 | set_window_title(filename); |
| 428 | } |
| 429 | |
| 430 | /**************************************************************************** |
| 431 | * read_cpel_callback |
| 432 | ****************************************************************************/ |
| 433 | |
| 434 | static void read_cpel_callback(GtkToggleButton *item, gpointer data) |
| 435 | { |
| 436 | |
| 437 | s_filesel = gtk_file_selection_new("Read CPEL data from..."); |
| 438 | |
| 439 | gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), |
| 440 | "cpel.out"); |
| 441 | |
| 442 | gtk_signal_connect (GTK_OBJECT ( |
| 443 | GTK_FILE_SELECTION(s_filesel)->ok_button), |
| 444 | "clicked", |
| 445 | GTK_SIGNAL_FUNC(get_cpel_name), NULL); |
| 446 | |
| 447 | gtk_signal_connect_object (GTK_OBJECT ( |
| 448 | GTK_FILE_SELECTION(s_filesel)->ok_button), |
| 449 | "clicked", |
| 450 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 451 | (gpointer) s_filesel); |
| 452 | |
| 453 | gtk_signal_connect_object (GTK_OBJECT ( |
| 454 | GTK_FILE_SELECTION(s_filesel)->cancel_button), |
| 455 | "clicked", |
| 456 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 457 | (gpointer) s_filesel); |
| 458 | gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); |
| 459 | gtk_widget_show (s_filesel); |
| 460 | } |
| 461 | |
| 462 | /**************************************************************************** |
| 463 | * read_clib_callback |
| 464 | ****************************************************************************/ |
| 465 | |
| 466 | static void read_clib_callback(GtkToggleButton *item, gpointer data) |
| 467 | { |
| 468 | |
| 469 | s_filesel = gtk_file_selection_new("Read clib data From..."); |
| 470 | |
| 471 | gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), |
| 472 | "clib.out"); |
| 473 | |
| 474 | gtk_signal_connect (GTK_OBJECT ( |
| 475 | GTK_FILE_SELECTION(s_filesel)->ok_button), |
| 476 | "clicked", |
| 477 | GTK_SIGNAL_FUNC(get_clib_name), NULL); |
| 478 | |
| 479 | gtk_signal_connect_object (GTK_OBJECT ( |
| 480 | GTK_FILE_SELECTION(s_filesel)->ok_button), |
| 481 | "clicked", |
| 482 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 483 | (gpointer) s_filesel); |
| 484 | |
| 485 | gtk_signal_connect_object (GTK_OBJECT ( |
| 486 | GTK_FILE_SELECTION(s_filesel)->cancel_button), |
| 487 | "clicked", |
| 488 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
| 489 | (gpointer) s_filesel); |
| 490 | gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); |
| 491 | gtk_widget_show (s_filesel); |
| 492 | } |
| 493 | |
| 494 | /**************************************************************************** |
| 495 | * menu1_init |
| 496 | ****************************************************************************/ |
| 497 | |
| 498 | void menu1_init(void) |
| 499 | { |
| 500 | |
| 501 | s_filemenu = gtk_menu_new(); |
| 502 | |
| 503 | s_readcpel = gtk_menu_item_new_with_label |
| 504 | ("Read CPEL file"); |
| 505 | gtk_menu_append(GTK_MENU(s_filemenu), s_readcpel); |
| 506 | gtk_signal_connect(GTK_OBJECT(s_readcpel), "activate", |
| 507 | GTK_SIGNAL_FUNC(read_cpel_callback), 0); |
| 508 | |
| 509 | s_readclib = gtk_menu_item_new_with_label |
| 510 | ("Read CLIB file"); |
| 511 | gtk_menu_append(GTK_MENU(s_filemenu), s_readclib); |
| 512 | gtk_signal_connect(GTK_OBJECT(s_readclib), "activate", |
| 513 | GTK_SIGNAL_FUNC(read_clib_callback), 0); |
| 514 | |
| 515 | s_readdefs = gtk_menu_item_new_with_label ("Read Event Definitions"); |
| 516 | gtk_menu_append(GTK_MENU(s_filemenu), s_readdefs); |
| 517 | gtk_signal_connect(GTK_OBJECT(s_readdefs), "activate", |
| 518 | GTK_SIGNAL_FUNC(read_eventdef_callback), 0); |
| 519 | |
| 520 | s_readevents = gtk_menu_item_new_with_label ("Read Event Log"); |
| 521 | gtk_menu_append(GTK_MENU(s_filemenu), s_readevents); |
| 522 | gtk_signal_connect(GTK_OBJECT(s_readevents), "activate", |
| 523 | GTK_SIGNAL_FUNC(read_events_callback), 0); |
| 524 | |
| 525 | s_readeventsclock = gtk_menu_item_new_with_label |
| 526 | ("Read Event Log with Different Clock Rate"); |
| 527 | gtk_menu_append(GTK_MENU(s_filemenu), s_readeventsclock); |
| 528 | gtk_signal_connect(GTK_OBJECT(s_readeventsclock), "activate", |
| 529 | GTK_SIGNAL_FUNC(read_eventsclock_callback), 0); |
| 530 | |
| 531 | s_print = gtk_menu_item_new_with_label ("Print"); |
| 532 | gtk_menu_append(GTK_MENU(s_filemenu), s_print); |
| 533 | gtk_signal_connect(GTK_OBJECT(s_print), "activate", |
| 534 | GTK_SIGNAL_FUNC(view1_print_callback), 0); |
| 535 | |
| 536 | s_quit = gtk_menu_item_new_with_label ("Exit"); |
| 537 | gtk_menu_append(GTK_MENU(s_filemenu), s_quit); |
| 538 | gtk_signal_connect(GTK_OBJECT(s_quit), "activate", |
| 539 | GTK_SIGNAL_FUNC(gtk_main_quit), 0); |
| 540 | |
| 541 | s_mainfilemenu = gtk_menu_item_new_with_label("File"); |
| 542 | gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainfilemenu), s_filemenu); |
| 543 | |
| 544 | s_helpmenu = gtk_menu_new(); |
| 545 | |
| 546 | s_help_general = gtk_menu_item_new_with_label ("General"); |
| 547 | gtk_menu_append(GTK_MENU(s_helpmenu), s_help_general); |
| 548 | gtk_signal_connect(GTK_OBJECT(s_help_general), "activate", |
| 549 | GTK_SIGNAL_FUNC(help_general_callback), 0); |
| 550 | |
| 551 | s_help_about = gtk_menu_item_new_with_label ("About"); |
| 552 | gtk_menu_append(GTK_MENU(s_helpmenu), s_help_about); |
| 553 | gtk_signal_connect(GTK_OBJECT(s_help_about), "activate", |
| 554 | GTK_SIGNAL_FUNC(help_about_callback), 0); |
| 555 | |
| 556 | s_mainhelpmenu = gtk_menu_item_new_with_label("Help"); |
| 557 | gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainhelpmenu), s_helpmenu); |
| 558 | |
| 559 | s_mainmenubar = gtk_menu_bar_new(); |
| 560 | gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainfilemenu); |
| 561 | gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainhelpmenu); |
| 562 | gtk_widget_show_all(s_mainmenubar); |
| 563 | |
| 564 | gtk_box_pack_start(GTK_BOX(g_mainvbox), s_mainmenubar, FALSE, FALSE, 0); |
| 565 | } |