diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-06-22 14:46:25 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-06-22 14:46:25 -0400 |
| commit | fd68befeefa2d962b445a4e68cc77f4f1e16e500 (patch) | |
| tree | c422e95829d379f158cd3349aacc5fac2ff1114f | |
| parent | 9d7b837596590d6b5ae98811acdc3c1dc8781a73 (diff) | |
kernelshark: Make ~/.trace-cmd/filters store filters
Have the filters stored locally in the users .trace-cmd directory.
This will allow the filters to be read and saved from there.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | kernel-shark.c | 308 | ||||
| -rw-r--r-- | kernel-shark.h | 2 |
2 files changed, 279 insertions, 31 deletions
diff --git a/kernel-shark.c b/kernel-shark.c index bab1728..5823934 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <string.h> | 23 | #include <string.h> |
| 24 | #include <stdarg.h> | 24 | #include <stdarg.h> |
| 25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
| 26 | #include <dirent.h> | ||
| 26 | #include <sys/types.h> | 27 | #include <sys/types.h> |
| 27 | #include <sys/stat.h> | 28 | #include <sys/stat.h> |
| 28 | #include <unistd.h> | 29 | #include <unistd.h> |
| @@ -35,6 +36,7 @@ | |||
| 35 | #include "trace-cmd.h" | 36 | #include "trace-cmd.h" |
| 36 | #include "trace-gui.h" | 37 | #include "trace-gui.h" |
| 37 | #include "kernel-shark.h" | 38 | #include "kernel-shark.h" |
| 39 | #include "util.h" | ||
| 38 | #include "version.h" | 40 | #include "version.h" |
| 39 | 41 | ||
| 40 | #define ___stringify(X) #X | 42 | #define ___stringify(X) #X |
| @@ -211,6 +213,7 @@ static void free_info(struct shark_info *info) | |||
| 211 | 213 | ||
| 212 | kernel_shark_clear_capture(info); | 214 | kernel_shark_clear_capture(info); |
| 213 | 215 | ||
| 216 | free(info->current_filter); | ||
| 214 | free(info->ginfo); | 217 | free(info->ginfo); |
| 215 | free(info); | 218 | free(info); |
| 216 | } | 219 | } |
| @@ -345,11 +348,52 @@ load_clicked (gpointer data) | |||
| 345 | g_free(filename); | 348 | g_free(filename); |
| 346 | } | 349 | } |
| 347 | 350 | ||
| 348 | /* Callback for the clicked signal of the Load Filters button */ | 351 | static GString *get_home_filters_new(void) |
| 349 | static void | 352 | { |
| 350 | load_filters_clicked (gpointer data) | 353 | char *path = getenv("HOME"); |
| 354 | GString *str; | ||
| 355 | |||
| 356 | str = g_string_new(path); | ||
| 357 | g_string_append(str, "/.trace-cmd/filters/"); | ||
| 358 | return str; | ||
| 359 | } | ||
| 360 | |||
| 361 | static int create_home_filters(void) | ||
| 362 | { | ||
| 363 | char *path = getenv("HOME"); | ||
| 364 | GString *str; | ||
| 365 | struct stat st; | ||
| 366 | int ret; | ||
| 367 | |||
| 368 | str = g_string_new(path); | ||
| 369 | g_string_append(str, "/.trace-cmd"); | ||
| 370 | ret = stat(str->str, &st); | ||
| 371 | if (ret < 0) { | ||
| 372 | ret = mkdir(str->str, 0755); | ||
| 373 | if (ret < 0) { | ||
| 374 | warning("Can not create %s", str->str); | ||
| 375 | goto out; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | g_string_append(str, "/filters"); | ||
| 380 | ret = stat(str->str, &st); | ||
| 381 | if (ret < 0) { | ||
| 382 | ret = mkdir(str->str, 0755); | ||
| 383 | if (ret < 0) { | ||
| 384 | warning("Can not create %s", str->str); | ||
| 385 | goto out; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | ret = 0; | ||
| 390 | out: | ||
| 391 | g_string_free(str, TRUE); | ||
| 392 | return ret; | ||
| 393 | } | ||
| 394 | |||
| 395 | static void load_filter(struct shark_info *info, const char *filename) | ||
| 351 | { | 396 | { |
| 352 | struct shark_info *info = data; | ||
| 353 | struct graph_info *ginfo = info->ginfo; | 397 | struct graph_info *ginfo = info->ginfo; |
| 354 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | 398 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); |
| 355 | GtkTreeModel *model; | 399 | GtkTreeModel *model; |
| @@ -358,18 +402,12 @@ load_filters_clicked (gpointer data) | |||
| 358 | struct filter_task *task_filter; | 402 | struct filter_task *task_filter; |
| 359 | struct filter_task *hide_tasks; | 403 | struct filter_task *hide_tasks; |
| 360 | struct event_filter *event_filter; | 404 | struct event_filter *event_filter; |
| 361 | gchar *filename; | ||
| 362 | int ret; | 405 | int ret; |
| 363 | 406 | ||
| 364 | filename = trace_get_file_dialog_filter("Load Filters", NULL, | ||
| 365 | TRACE_DIALOG_FILTER_FILTER, FALSE); | ||
| 366 | if (!filename) | ||
| 367 | return; | ||
| 368 | |||
| 369 | handle = tracecmd_xml_open(filename); | 407 | handle = tracecmd_xml_open(filename); |
| 370 | if (!handle) { | 408 | if (!handle) { |
| 371 | warning("Could not open %s", filename); | 409 | warning("Could not open %s", filename); |
| 372 | goto out; | 410 | return; |
| 373 | } | 411 | } |
| 374 | 412 | ||
| 375 | /* Unsync the list and graph filters */ | 413 | /* Unsync the list and graph filters */ |
| @@ -423,40 +461,61 @@ load_filters_clicked (gpointer data) | |||
| 423 | 461 | ||
| 424 | model = gtk_tree_view_get_model(trace_tree); | 462 | model = gtk_tree_view_get_model(trace_tree); |
| 425 | if (!model) | 463 | if (!model) |
| 426 | goto out; | 464 | return; |
| 427 | 465 | ||
| 428 | store = TRACE_VIEW_STORE(model); | 466 | store = TRACE_VIEW_STORE(model); |
| 429 | event_filter = trace_view_store_get_event_filter(store); | 467 | event_filter = trace_view_store_get_event_filter(store); |
| 430 | 468 | ||
| 431 | if (pevent_filter_compare(event_filter, ginfo->event_filter)) | 469 | if (pevent_filter_compare(event_filter, ginfo->event_filter)) |
| 432 | sync_event_filters(info); | 470 | sync_event_filters(info); |
| 471 | } | ||
| 433 | 472 | ||
| 434 | out: | 473 | static void load_filter_clicked(GtkMenuItem *item, gpointer data) |
| 435 | g_free(filename); | 474 | { |
| 475 | struct shark_info *info = data; | ||
| 476 | const char *name; | ||
| 477 | GString *path; | ||
| 478 | |||
| 479 | name = gtk_menu_item_get_label(item); | ||
| 480 | |||
| 481 | path = get_home_filters_new(); | ||
| 482 | g_string_append_printf(path, "/%s.ksf", name); | ||
| 483 | |||
| 484 | load_filter(info, path->str); | ||
| 485 | g_string_free(path, TRUE); | ||
| 436 | 486 | ||
| 487 | free(info->current_filter); | ||
| 488 | info->current_filter = strdup(name); | ||
| 437 | } | 489 | } |
| 438 | 490 | ||
| 439 | /* Callback for the clicked signal of the Save Filters button */ | 491 | /* Callback for the clicked signal of the Load Filters button */ |
| 440 | static void | 492 | static void |
| 441 | save_filters_clicked (gpointer data) | 493 | import_filters_clicked (gpointer data) |
| 442 | { | 494 | { |
| 443 | struct shark_info *info = data; | 495 | struct shark_info *info = data; |
| 496 | gchar *filename; | ||
| 497 | |||
| 498 | filename = trace_get_file_dialog_filter("Load Filters", NULL, | ||
| 499 | TRACE_DIALOG_FILTER_FILTER, FALSE); | ||
| 500 | if (!filename) | ||
| 501 | return; | ||
| 502 | |||
| 503 | load_filter(info, filename); | ||
| 504 | } | ||
| 505 | |||
| 506 | static void save_filters(struct shark_info *info, const char *filename) | ||
| 507 | { | ||
| 444 | struct graph_info *ginfo = info->ginfo; | 508 | struct graph_info *ginfo = info->ginfo; |
| 445 | struct tracecmd_xml_handle *handle; | 509 | struct tracecmd_xml_handle *handle; |
| 446 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | 510 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); |
| 447 | struct filter_task *task_filter; | 511 | struct filter_task *task_filter; |
| 448 | struct filter_task *hide_tasks; | 512 | struct filter_task *hide_tasks; |
| 449 | gchar *filename; | ||
| 450 | |||
| 451 | filename = trace_get_file_dialog_filter("Save Filters", "Save", | ||
| 452 | TRACE_DIALOG_FILTER_FILTER, TRUE); | ||
| 453 | if (!filename) | ||
| 454 | return; | ||
| 455 | 513 | ||
| 456 | handle = tracecmd_xml_create(filename, VERSION_STRING); | 514 | handle = tracecmd_xml_create(filename, VERSION_STRING); |
| 457 | if (!handle) | 515 | if (!handle) { |
| 458 | warning("Could not create %s", filename); | 516 | warning("Could not create %s", filename); |
| 459 | g_free(filename); | 517 | return; |
| 518 | } | ||
| 460 | 519 | ||
| 461 | trace_view_save_filters(handle, trace_tree); | 520 | trace_view_save_filters(handle, trace_tree); |
| 462 | trace_graph_save_filters(ginfo, handle); | 521 | trace_graph_save_filters(ginfo, handle); |
| @@ -481,6 +540,178 @@ save_filters_clicked (gpointer data) | |||
| 481 | tracecmd_xml_close(handle); | 540 | tracecmd_xml_close(handle); |
| 482 | } | 541 | } |
| 483 | 542 | ||
| 543 | /* Callback for the clicked signal of the Save Filters button */ | ||
| 544 | static void | ||
| 545 | export_filters_clicked (gpointer data) | ||
| 546 | { | ||
| 547 | struct shark_info *info = data; | ||
| 548 | gchar *filename; | ||
| 549 | |||
| 550 | filename = trace_get_file_dialog_filter("Save Filters", "Save", | ||
| 551 | TRACE_DIALOG_FILTER_FILTER, TRUE); | ||
| 552 | if (!filename) | ||
| 553 | return; | ||
| 554 | |||
| 555 | save_filters(info, filename); | ||
| 556 | g_free(filename); | ||
| 557 | } | ||
| 558 | |||
| 559 | static void update_load_filter(struct shark_info *info) | ||
| 560 | { | ||
| 561 | struct dirent *dent; | ||
| 562 | struct stat st; | ||
| 563 | DIR *dir; | ||
| 564 | GtkWidget *menu; | ||
| 565 | GtkWidget *sub_item; | ||
| 566 | GString *path; | ||
| 567 | int ret; | ||
| 568 | |||
| 569 | path = get_home_filters_new(); | ||
| 570 | |||
| 571 | menu = gtk_menu_new(); | ||
| 572 | |||
| 573 | ret = stat(path->str, &st); | ||
| 574 | if (ret < 0 || !S_ISDIR(st.st_mode)) | ||
| 575 | goto update_rest; | ||
| 576 | |||
| 577 | dir = opendir(path->str); | ||
| 578 | if (!dir) | ||
| 579 | goto update_rest; | ||
| 580 | |||
| 581 | while ((dent = readdir(dir))) { | ||
| 582 | const char *name = dent->d_name; | ||
| 583 | GString *file; | ||
| 584 | gchar *item; | ||
| 585 | |||
| 586 | if (strcmp(name, ".") == 0 || | ||
| 587 | strcmp(name, "..") == 0) | ||
| 588 | continue; | ||
| 589 | |||
| 590 | if (strcmp(name + strlen(name) - 4, ".ksf") != 0) | ||
| 591 | continue; | ||
| 592 | |||
| 593 | file = g_string_new(path->str); | ||
| 594 | g_string_append_printf(file, "/%s", name); | ||
| 595 | |||
| 596 | /* Save the file name but remove the .kss extention */ | ||
| 597 | item = g_strdup(name); | ||
| 598 | item[strlen(name) - 4] = 0; | ||
| 599 | |||
| 600 | sub_item = gtk_menu_item_new_with_label(item); | ||
| 601 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 602 | gtk_widget_show(sub_item); | ||
| 603 | |||
| 604 | g_signal_connect(G_OBJECT (sub_item), "activate", | ||
| 605 | G_CALLBACK (load_filter_clicked), | ||
| 606 | (gpointer) info); | ||
| 607 | |||
| 608 | g_free(item); | ||
| 609 | g_string_free(file, TRUE); | ||
| 610 | } | ||
| 611 | |||
| 612 | update_rest: | ||
| 613 | g_string_free(path, TRUE); | ||
| 614 | |||
| 615 | /* --- File - Load Filter - Filters --- */ | ||
| 616 | |||
| 617 | sub_item = gtk_menu_item_new_with_label("Import Filter"); | ||
| 618 | |||
| 619 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 620 | G_CALLBACK (import_filters_clicked), | ||
| 621 | (gpointer) info); | ||
| 622 | |||
| 623 | /* Add them to the menu */ | ||
| 624 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 625 | |||
| 626 | /* We do need to show menu items */ | ||
| 627 | gtk_widget_show(sub_item); | ||
| 628 | |||
| 629 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (info->load_filter_menu), menu); | ||
| 630 | |||
| 631 | } | ||
| 632 | |||
| 633 | /* Callback for the clicked signal of the Save Filters button */ | ||
| 634 | static void | ||
| 635 | save_filter_clicked (gpointer data) | ||
| 636 | { | ||
| 637 | struct shark_info *info = data; | ||
| 638 | struct stat st; | ||
| 639 | GtkWidget *dialog; | ||
| 640 | GtkWidget *hbox; | ||
| 641 | GtkWidget *label; | ||
| 642 | GtkWidget *entry; | ||
| 643 | GString *file; | ||
| 644 | const char *name; | ||
| 645 | gint result; | ||
| 646 | int ret; | ||
| 647 | |||
| 648 | dialog = gtk_dialog_new_with_buttons("Save Filter", | ||
| 649 | NULL, | ||
| 650 | GTK_DIALOG_MODAL, | ||
| 651 | GTK_STOCK_OK, | ||
| 652 | GTK_RESPONSE_ACCEPT, | ||
| 653 | GTK_STOCK_CANCEL, | ||
| 654 | GTK_RESPONSE_REJECT, | ||
| 655 | NULL); | ||
| 656 | |||
| 657 | hbox = gtk_hbox_new(FALSE, 0); | ||
| 658 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, FALSE, 0); | ||
| 659 | gtk_widget_show(hbox); | ||
| 660 | |||
| 661 | label = gtk_label_new("Filter Name: "); | ||
| 662 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | ||
| 663 | gtk_widget_show(label); | ||
| 664 | |||
| 665 | entry = gtk_entry_new(); | ||
| 666 | gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); | ||
| 667 | gtk_widget_show(entry); | ||
| 668 | |||
| 669 | if (info->current_filter) | ||
| 670 | gtk_entry_set_text(GTK_ENTRY(entry), info->current_filter); | ||
| 671 | |||
| 672 | again: | ||
| 673 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 674 | switch (result) { | ||
| 675 | case GTK_RESPONSE_ACCEPT: | ||
| 676 | name = gtk_entry_get_text(GTK_ENTRY(entry)); | ||
| 677 | if (!name || !has_text(name)) { | ||
| 678 | warning("Must enter a name"); | ||
| 679 | goto again; | ||
| 680 | } | ||
| 681 | /* Make sure home settings exists */ | ||
| 682 | if (create_home_filters() < 0) | ||
| 683 | break; | ||
| 684 | file = get_home_filters_new(); | ||
| 685 | g_string_append_printf(file, "/%s.ksf", name); | ||
| 686 | ret = stat(file->str, &st); | ||
| 687 | if (ret >= 0) { | ||
| 688 | ret = trace_dialog(GTK_WINDOW(dialog), TRACE_GUI_ASK, | ||
| 689 | "The Filter '%s' already exists.\n" | ||
| 690 | "Are you sure you want to replace it", | ||
| 691 | name); | ||
| 692 | if (ret == GTK_RESPONSE_NO) { | ||
| 693 | g_string_free(file, TRUE); | ||
| 694 | goto again; | ||
| 695 | } | ||
| 696 | } | ||
| 697 | save_filters(info, file->str); | ||
| 698 | |||
| 699 | free(info->current_filter); | ||
| 700 | info->current_filter = strdup(name); | ||
| 701 | |||
| 702 | update_load_filter(info); | ||
| 703 | g_string_free(file, TRUE); | ||
| 704 | break; | ||
| 705 | |||
| 706 | case GTK_RESPONSE_REJECT: | ||
| 707 | break; | ||
| 708 | default: | ||
| 709 | break; | ||
| 710 | }; | ||
| 711 | |||
| 712 | gtk_widget_destroy(dialog); | ||
| 713 | } | ||
| 714 | |||
| 484 | /* Callback for the clicked signal of the Exit button */ | 715 | /* Callback for the clicked signal of the Exit button */ |
| 485 | static void | 716 | static void |
| 486 | exit_clicked (gpointer data) | 717 | exit_clicked (gpointer data) |
| @@ -1633,30 +1864,45 @@ void kernel_shark(int argc, char **argv) | |||
| 1633 | gtk_widget_show(sub_item); | 1864 | gtk_widget_show(sub_item); |
| 1634 | 1865 | ||
| 1635 | 1866 | ||
| 1636 | /* --- File - Load Filter Option --- */ | 1867 | /* --- File - Load Filter --- */ |
| 1637 | 1868 | ||
| 1638 | sub_item = gtk_menu_item_new_with_label("Load filters"); | 1869 | sub_item = gtk_menu_item_new_with_label("Load filter"); |
| 1639 | 1870 | ||
| 1640 | /* Add them to the menu */ | 1871 | /* Add them to the menu */ |
| 1641 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1872 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 1642 | 1873 | ||
| 1643 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1874 | info->load_filter_menu = sub_item; |
| 1644 | G_CALLBACK (load_filters_clicked), | ||
| 1645 | (gpointer) info); | ||
| 1646 | 1875 | ||
| 1647 | /* We do need to show menu items */ | 1876 | /* We do need to show menu items */ |
| 1648 | gtk_widget_show(sub_item); | 1877 | gtk_widget_show(sub_item); |
| 1649 | 1878 | ||
| 1879 | update_load_filter(info); | ||
| 1880 | |||
| 1650 | 1881 | ||
| 1651 | /* --- File - Save Filter Option --- */ | 1882 | /* --- File - Save Filter Option --- */ |
| 1652 | 1883 | ||
| 1653 | sub_item = gtk_menu_item_new_with_label("Save filters"); | 1884 | sub_item = gtk_menu_item_new_with_label("Save filter"); |
| 1885 | |||
| 1886 | /* Add them to the menu */ | ||
| 1887 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1888 | |||
| 1889 | /* We do need to show menu items */ | ||
| 1890 | gtk_widget_show(sub_item); | ||
| 1891 | |||
| 1892 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1893 | G_CALLBACK (save_filter_clicked), | ||
| 1894 | (gpointer) info); | ||
| 1895 | |||
| 1896 | |||
| 1897 | /* --- File - Export Filter Option --- */ | ||
| 1898 | |||
| 1899 | sub_item = gtk_menu_item_new_with_label("Export filters"); | ||
| 1654 | 1900 | ||
| 1655 | /* Add them to the menu */ | 1901 | /* Add them to the menu */ |
| 1656 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1902 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 1657 | 1903 | ||
| 1658 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1904 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
| 1659 | G_CALLBACK (save_filters_clicked), | 1905 | G_CALLBACK (export_filters_clicked), |
| 1660 | (gpointer) info); | 1906 | (gpointer) info); |
| 1661 | 1907 | ||
| 1662 | /* We do need to show menu items */ | 1908 | /* We do need to show menu items */ |
diff --git a/kernel-shark.h b/kernel-shark.h index e2e795c..c3f7b13 100644 --- a/kernel-shark.h +++ b/kernel-shark.h | |||
| @@ -30,6 +30,7 @@ struct shark_info { | |||
| 30 | struct tracecmd_input *handle; | 30 | struct tracecmd_input *handle; |
| 31 | GtkWidget *treeview; | 31 | GtkWidget *treeview; |
| 32 | GtkWidget *spin; | 32 | GtkWidget *spin; |
| 33 | GtkWidget *load_filter_menu; | ||
| 33 | GtkWidget *task_sync_menu; | 34 | GtkWidget *task_sync_menu; |
| 34 | GtkWidget *events_sync_menu; | 35 | GtkWidget *events_sync_menu; |
| 35 | GtkWidget *list_task_menu; | 36 | GtkWidget *list_task_menu; |
| @@ -40,6 +41,7 @@ struct shark_info { | |||
| 40 | GtkWidget *graph_events_menu; | 41 | GtkWidget *graph_events_menu; |
| 41 | GtkWidget *list_adv_events_menu; | 42 | GtkWidget *list_adv_events_menu; |
| 42 | GtkWidget *graph_adv_events_menu; | 43 | GtkWidget *graph_adv_events_menu; |
| 44 | gchar *current_filter; | ||
| 43 | struct graph_callbacks graph_cbs; | 45 | struct graph_callbacks graph_cbs; |
| 44 | gint selected_task; | 46 | gint selected_task; |
| 45 | gboolean list_filter_enabled; | 47 | gboolean list_filter_enabled; |
