From 7f8e445ad1f698d0e219801bdf70a5eeaf37dc04 Mon Sep 17 00:00:00 2001 From: Thierry Vignaud Date: Tue, 19 May 2020 01:56:15 +0200 Subject: sync Gtk4 fake package with gtk4-3.98.4 --- NEWS | 1 + fake_packages/Gtk4.pm | 211 +++++++++++++++++++++++++++++--------------------- 2 files changed, 122 insertions(+), 90 deletions(-) diff --git a/NEWS b/NEWS index ed51974..7c8935b 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ - fake packages: o kill fake packages for unused Gtk2 modules o kill fake package for unused Math::Int64 module + o sync Gtk4 fake package with gtk4-3.98.4 Version 1.2.38 - 28 April 2020, by Thierry Vignaud diff --git a/fake_packages/Gtk4.pm b/fake_packages/Gtk4.pm index 33c383d..64f468f 100644 --- a/fake_packages/Gtk4.pm +++ b/fake_packages/Gtk4.pm @@ -493,12 +493,13 @@ sub widget_set { } sub widget_unset { } package Gtk4::ActionBar; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub get_center_widget { } sub get_revealed { } sub new { } sub pack_end { } sub pack_start { } +sub remove { } sub set_center_widget { } sub set_revealed { } @@ -635,12 +636,14 @@ sub padding { } sub parent_class { } package Gtk4::AspectFrame; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); +sub get_child { } sub get_obey_child { } sub get_ratio { } sub get_xalign { } sub get_yalign { } sub new { } +sub set_child { } sub set_obey_child { } sub set_ratio { } sub set_xalign { } @@ -677,14 +680,6 @@ package Gtk4::AssistantPage; our @ISA = qw(GObject::Object); sub get_child { } -package Gtk4::Bin; -our @ISA = qw(Gtk4::Container); -sub get_child { } - -package Gtk4::BinClass; -sub padding { } -sub parent_class { } - package Gtk4::BinLayout; our @ISA = qw(Gtk4::LayoutManager); sub new { } @@ -705,12 +700,15 @@ sub right { } sub top { } package Gtk4::Box; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); +sub append { } sub get_baseline_position { } sub get_homogeneous { } sub get_spacing { } sub insert_child_after { } sub new { } +sub prepend { } +sub remove { } sub reorder_child_after { } sub set_baseline_position { } sub set_homogeneous { } @@ -814,7 +812,8 @@ sub get_type_from_function { } sub get_type_from_name { } package Gtk4::Button; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); +sub get_child { } sub get_has_frame { } sub get_icon_name { } sub get_label { } @@ -822,6 +821,7 @@ sub get_use_underline { } sub new_from_icon_name { } sub new_with_label { } sub new_with_mnemonic { } +sub set_child { } sub set_has_frame { } sub set_icon_name { } sub set_label { } @@ -1202,11 +1202,12 @@ our @ISA = qw(Gtk4::Widget); sub new { } package Gtk4::ComboBox; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub get_active { } sub get_active_id { } sub get_active_iter { } sub get_button_sensitivity { } +sub get_child { } sub get_entry_text_column { } sub get_has_entry { } sub get_id_column { } @@ -1224,6 +1225,7 @@ sub set_active { } sub set_active_id { } sub set_active_iter { } sub set_button_sensitivity { } +sub set_child { } sub set_entry_text_column { } sub set_id_column { } sub set_model { } @@ -1313,20 +1315,6 @@ sub parent_class { } package Gtk4::ConstraintVflParserError; sub quark { } -package Gtk4::Container; -our @ISA = qw(Gtk4::Widget); -sub add { } -sub child_type { } -sub forall { } -sub Gtk4::Container::foreach { } -sub get_children { } -sub remove { } - -package Gtk4::ContainerAccessibleClass; -sub add_gtk { } -sub parent_class { } -sub remove_gtk { } - package Gtk4::ContainerCellAccessible; sub add_child { } sub get_children { } @@ -1336,14 +1324,6 @@ sub remove_child { } package Gtk4::ContainerCellAccessibleClass; sub parent_class { } -package Gtk4::ContainerClass; -sub add { } -sub child_type { } -sub forall { } -sub padding { } -sub parent_class { } -sub remove { } - package Gtk4::CssLocation; sub bytes { } sub chars { } @@ -1371,6 +1351,10 @@ sub ref { } sub to_string { } sub unref { } +package Gtk4::CustomLayout; +our @ISA = qw(Gtk4::LayoutManager); +sub new { } + package Gtk4::CustomLayoutClass; sub parent_class { } @@ -1386,7 +1370,7 @@ sub parent_class { } sub response { } package Gtk4::DragIcon; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub create_widget_for_value { } sub get_child { } sub get_for_drag { } @@ -1419,6 +1403,7 @@ sub set_draw_func { } package Gtk4::DrawingAreaClass; sub padding { } sub parent_class { } +sub resize { } package Gtk4::DropControllerMotion; our @ISA = qw(Gtk4::EventController); @@ -1662,7 +1647,8 @@ sub new { } sub set_flags { } package Gtk4::Expander; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); +sub get_child { } sub get_expanded { } sub get_label { } sub get_label_widget { } @@ -1671,6 +1657,7 @@ sub get_use_markup { } sub get_use_underline { } sub new { } sub new_with_mnemonic { } +sub set_child { } sub set_expanded { } sub set_label { } sub set_label_widget { } @@ -1776,12 +1763,13 @@ package Gtk4::FilterListModelClass; sub parent_class { } package Gtk4::Fixed; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub get_child_position { } sub get_child_transform { } sub move { } sub new { } sub put { } +sub remove { } sub set_child_transform { } package Gtk4::FixedClass; @@ -1814,7 +1802,7 @@ package Gtk4::FlattenListModelClass; sub parent_class { } package Gtk4::FlowBox; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub bind_model { } sub get_activate_on_single_click { } sub get_child_at_index { } @@ -1830,6 +1818,7 @@ sub insert { } sub invalidate_filter { } sub invalidate_sort { } sub new { } +sub remove { } sub select_all { } sub select_child { } sub selected_foreach { } @@ -1851,11 +1840,13 @@ package Gtk4::FlowBoxAccessibleClass; sub parent_class { } package Gtk4::FlowBoxChild; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub changed { } +sub get_child { } sub get_index { } sub is_selected { } sub new { } +sub set_child { } package Gtk4::FlowBoxChildAccessibleClass; sub parent_class { } @@ -1918,11 +1909,13 @@ our @ISA = qw(Gtk4::Widget); sub new { } package Gtk4::Frame; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); +sub get_child { } sub get_label { } sub get_label_align { } sub get_label_widget { } sub new { } +sub set_child { } sub set_label { } sub set_label_align { } sub set_label_widget { } @@ -4479,9 +4472,8 @@ sub get_default { } sub get_default_group { } sub get_default_seat { } sub get_event { } -sub get_monitor { } sub get_monitor_at_surface { } -sub get_n_monitors { } +sub get_monitors { } sub get_name { } sub get_primary_clipboard { } sub get_setting { } @@ -4498,7 +4490,6 @@ sub open { } sub peek_event { } sub put_event { } sub supports_input_shapes { } -sub supports_shapes { } sub sync { } package Gtk4::Gdk::DisplayManager; @@ -4885,8 +4876,6 @@ sub get_slaves { } package Gtk4::Gdk::Surface; our @ISA = qw(GObject::Object); sub beep { } -sub begin_move_drag { } -sub begin_resize_drag { } sub create_cairo_context { } sub create_gl_context { } sub create_similar_surface { } @@ -4905,7 +4894,6 @@ sub get_support_multidevice { } sub get_width { } sub hide { } sub is_destroyed { } -sub is_viewable { } sub new_popup { } sub new_toplevel { } sub queue_expose { } @@ -4933,6 +4921,8 @@ sub axes { } sub time { } package Gtk4::Gdk::Toplevel; +sub begin_move { } +sub begin_resize { } sub focus { } sub get_state { } sub inhibit_system_shortcuts { } @@ -4990,7 +4980,6 @@ sub x11_get_server_time { } sub x11_get_xatom_by_name_for_display { } sub x11_get_xatom_name_for_display { } sub x11_lookup_xdisplay { } -sub x11_register_standard_event_type { } sub x11_set_sm_client_id { } package Gtk4::GdkX11::X11Display; @@ -5067,9 +5056,7 @@ sub ungroup { } package Gtk4::GestureClick; our @ISA = qw(Gtk4::GestureSingle); -sub get_area { } sub new { } -sub set_area { } package Gtk4::GestureDrag; our @ISA = qw(Gtk4::GestureSingle); @@ -5124,7 +5111,7 @@ sub get_scale_delta { } sub new { } package Gtk4::Grid; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub attach { } sub attach_next_to { } sub get_baseline_row { } @@ -5139,6 +5126,7 @@ sub insert_next_to { } sub insert_row { } sub new { } sub query_child { } +sub remove { } sub remove_column { } sub remove_row { } sub set_baseline_row { } @@ -5186,22 +5174,17 @@ package Gtk4::GridLayoutClass; sub parent_class { } package Gtk4::HeaderBar; -our @ISA = qw(Gtk4::Container); -sub get_custom_title { } +our @ISA = qw(Gtk4::Widget); sub get_decoration_layout { } -sub get_has_subtitle { } sub get_show_title_buttons { } -sub get_subtitle { } -sub get_title { } +sub get_title_widget { } sub new { } sub pack_end { } sub pack_start { } -sub set_custom_title { } +sub remove { } sub set_decoration_layout { } -sub set_has_subtitle { } sub set_show_title_buttons { } -sub set_subtitle { } -sub set_title { } +sub set_title_widget { } package Gtk4::IMContext; our @ISA = qw(GObject::Object); @@ -5282,7 +5265,7 @@ package Gtk4::IconThemeError; sub quark { } package Gtk4::IconView; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub create_drag_icon { } sub enable_model_drag_dest { } sub enable_model_drag_source { } @@ -5376,10 +5359,13 @@ package Gtk4::ImageCellAccessibleClass; sub parent_class { } package Gtk4::InfoBar; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); +sub add_child { } sub get_message_type { } sub get_revealed { } sub get_show_close_button { } +sub remove_action_widget { } +sub remove_child { } sub set_message_type { } sub set_revealed { } sub set_show_close_button { } @@ -5504,7 +5490,7 @@ package Gtk4::LinkButtonAccessibleClass; sub parent_class { } package Gtk4::ListBox; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub bind_model { } sub drag_highlight_row { } sub drag_unhighlight_row { } @@ -5522,6 +5508,7 @@ sub invalidate_headers { } sub invalidate_sort { } sub new { } sub prepend { } +sub remove { } sub select_all { } sub select_row { } sub selected_foreach { } @@ -5540,15 +5527,17 @@ package Gtk4::ListBoxAccessibleClass; sub parent_class { } package Gtk4::ListBoxRow; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub changed { } sub get_activatable { } +sub get_child { } sub get_header { } sub get_index { } sub get_selectable { } sub is_selected { } sub new { } sub set_activatable { } +sub set_child { } sub set_header { } sub set_selectable { } @@ -5734,6 +5723,7 @@ sub check_resize { } sub get_for_surface { } sub get_renderer { } sub get_surface { } +sub get_surface_transform { } package Gtk4::NativeDialog; our @ISA = qw(GObject::Object); @@ -5743,7 +5733,6 @@ sub get_title { } sub get_transient_for { } sub get_visible { } sub hide { } -sub run { } sub set_modal { } sub set_title { } sub set_transient_for { } @@ -5775,7 +5764,7 @@ package Gtk4::NoSelectionClass; sub parent_class { } package Gtk4::Notebook; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub append_page { } sub append_page_menu { } sub detach_tab { } @@ -5849,11 +5838,14 @@ package Gtk4::OrientableIface; sub base_iface { } package Gtk4::Overlay; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub add_overlay { } +sub get_child { } sub get_clip_overlay { } sub get_measure_overlay { } sub new { } +sub remove_overlay { } +sub set_child { } sub set_clip_overlay { } sub set_measure_overlay { } @@ -5905,17 +5897,23 @@ sub to_gvariant { } sub to_key_file { } package Gtk4::Paned; -our @ISA = qw(Gtk4::Container); -sub add1 { } -sub add2 { } -sub get_child1 { } -sub get_child2 { } +our @ISA = qw(Gtk4::Widget); +sub get_end_child { } sub get_position { } +sub get_resize_end_child { } +sub get_resize_start_child { } +sub get_shrink_end_child { } +sub get_shrink_start_child { } +sub get_start_child { } sub get_wide_handle { } sub new { } -sub pack1 { } -sub pack2 { } +sub set_end_child { } sub set_position { } +sub set_resize_end_child { } +sub set_resize_start_child { } +sub set_shrink_end_child { } +sub set_shrink_start_child { } +sub set_start_child { } sub set_wide_handle { } package Gtk4::PanedAccessibleClass; @@ -5982,8 +5980,9 @@ package Gtk4::PictureClass; sub parent_class { } package Gtk4::Popover; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub get_autohide { } +sub get_child { } sub get_has_arrow { } sub get_mnemonics_visible { } sub get_pointing_to { } @@ -5992,6 +5991,7 @@ sub new { } sub popdown { } sub popup { } sub set_autohide { } +sub set_child { } sub set_default_widget { } sub set_has_arrow { } sub set_mnemonics_visible { } @@ -6320,12 +6320,14 @@ sub new { } sub width { } package Gtk4::Revealer; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); +sub get_child { } sub get_child_revealed { } sub get_reveal_child { } sub get_transition_duration { } sub get_transition_type { } sub new { } +sub set_child { } sub set_reveal_child { } sub set_transition_duration { } sub set_transition_type { } @@ -6406,8 +6408,9 @@ package Gtk4::ScrollbarAccessibleClass; sub parent_class { } package Gtk4::ScrolledWindow; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub get_capture_button_press { } +sub get_child { } sub get_hadjustment { } sub get_has_frame { } sub get_hscrollbar { } @@ -6425,6 +6428,7 @@ sub get_vadjustment { } sub get_vscrollbar { } sub new { } sub set_capture_button_press { } +sub set_child { } sub set_hadjustment { } sub set_has_frame { } sub set_kinetic_scrolling { } @@ -6444,12 +6448,14 @@ package Gtk4::ScrolledWindowAccessibleClass; sub parent_class { } package Gtk4::SearchBar; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub connect_entry { } +sub get_child { } sub get_key_capture_widget { } sub get_search_mode { } sub get_show_close_button { } sub new { } +sub set_child { } sub set_key_capture_widget { } sub set_search_mode { } sub set_show_close_button { } @@ -6692,7 +6698,7 @@ package Gtk4::SpinnerAccessibleClass; sub parent_class { } package Gtk4::Stack; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub add_named { } sub add_titled { } sub get_child_by_name { } @@ -6708,6 +6714,7 @@ sub get_vhomogeneous { } sub get_visible_child { } sub get_visible_child_name { } sub new { } +sub remove { } sub set_hhomogeneous { } sub set_homogeneous { } sub set_interpolate_size { } @@ -6764,7 +6771,6 @@ sub get_padding { } sub get_scale { } sub get_state { } sub has_class { } -sub list_classes { } sub lookup_color { } sub remove_class { } sub remove_provider { } @@ -7062,7 +7068,7 @@ sub new { } sub remove { } package Gtk4::TextView; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub add_child_at_anchor { } sub add_overlay { } sub backward_display_line { } @@ -7105,6 +7111,7 @@ sub move_visually { } sub new { } sub new_with_buffer { } sub place_cursor_onscreen { } +sub remove { } sub reset_cursor_blink { } sub reset_im_context { } sub scroll_mark_onscreen { } @@ -7417,7 +7424,7 @@ sub padding { } sub parent_class { } package Gtk4::TreeView; -our @ISA = qw(Gtk4::Container); +our @ISA = qw(Gtk4::Widget); sub append_column { } sub collapse_all { } sub collapse_row { } @@ -7585,9 +7592,11 @@ package Gtk4::VideoClass; sub parent_class { } package Gtk4::Viewport; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); +sub get_child { } sub get_scroll_to_focus { } sub new { } +sub set_child { } sub set_scroll_to_focus { } package Gtk4::VolumeButton; @@ -7613,8 +7622,6 @@ sub compute_transform { } sub contains { } sub create_pango_context { } sub create_pango_layout { } -sub destroy { } -sub destroyed { } sub device_is_shadowed { } sub drag_check_threshold { } sub error_bell { } @@ -7637,6 +7644,7 @@ sub get_display { } sub get_first_child { } sub get_focus_child { } sub get_focus_on_click { } +sub get_focusable { } sub get_font_map { } sub get_font_options { } sub get_frame_clock { } @@ -7685,7 +7693,6 @@ sub grab_focus { } sub has_css_class { } sub has_default { } sub has_focus { } -sub has_grab { } sub has_visible_focus { } sub hide { } sub in_destruction { } @@ -7714,7 +7721,6 @@ sub remove_controller { } sub remove_css_class { } sub remove_mnemonic_label { } sub remove_tick_callback { } -sub reset_style { } sub set_can_focus { } sub set_can_target { } sub set_child_visible { } @@ -7725,6 +7731,7 @@ sub set_default_direction { } sub set_direction { } sub set_focus_child { } sub set_focus_on_click { } +sub set_focusable { } sub set_font_map { } sub set_font_options { } sub set_halign { } @@ -7774,7 +7781,6 @@ sub bind_template_child_full { } sub compute_expand { } sub contains { } sub css_changed { } -sub destroy { } sub direction_changed { } sub focus { } sub get_accessible { } @@ -7784,6 +7790,7 @@ sub get_request_mode { } sub grab_focus { } sub grab_notify { } sub hide { } +sub install_action { } sub install_property_action { } sub keynav_failed { } sub map { } @@ -7809,6 +7816,7 @@ sub show { } sub size_allocate { } sub snapshot { } sub state_flags_changed { } +sub system_setting_changed { } sub unmap { } sub unrealize { } sub unroot { } @@ -7823,11 +7831,13 @@ package Gtk4::WidgetPaintableClass; sub parent_class { } package Gtk4::Window; -our @ISA = qw(Gtk4::Bin); +our @ISA = qw(Gtk4::Widget); sub close { } +sub destroy { } sub fullscreen { } sub fullscreen_on_monitor { } sub get_application { } +sub get_child { } sub get_decorated { } sub get_default_icon_name { } sub get_default_size { } @@ -7858,6 +7868,7 @@ sub present_with_time { } sub resize { } sub set_application { } sub set_auto_startup_notification { } +sub set_child { } sub set_decorated { } sub set_default_icon_name { } sub set_default_size { } @@ -7867,7 +7878,6 @@ sub set_destroy_with_parent { } sub set_display { } sub set_focus { } sub set_focus_visible { } -sub set_has_user_ref_count { } sub set_hide_on_close { } sub set_icon_name { } sub set_interactive_debugging { } @@ -7894,6 +7904,18 @@ sub keys_changed { } sub padding { } sub parent_class { } +package Gtk4::WindowControls; +our @ISA = qw(Gtk4::Widget); +sub get_decoration_layout { } +sub get_empty { } +sub get_side { } +sub new { } +sub set_decoration_layout { } +sub set_side { } + +package Gtk4::WindowControlsClass; +sub parent_class { } + package Gtk4::WindowGroup; our @ISA = qw(GObject::Object); sub add_window { } @@ -7904,6 +7926,15 @@ sub remove_window { } package Gtk4::WindowGroupClass; sub parent_class { } +package Gtk4::WindowHandle; +our @ISA = qw(Gtk4::Widget); +sub get_child { } +sub new { } +sub set_child { } + +package Gtk4::WindowHandleClass; +sub parent_class { } + package Pango; sub ANALYSIS_FLAG_CENTERED_BASELINE { } sub ANALYSIS_FLAG_IS_ELLIPSIS { } -- cgit v1.2.1 /a> 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
<!-- <!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> -->
<chapter id="customization">
  <title>Customising Bugzilla</title>

  <section id="cust-templates">
    <title>Template Customization</title>
    
    <para>
      Administrators can configure the look and feel of Bugzilla without
      having to edit Perl files or face the nightmare of massive merge
      conflicts when they upgrade to a newer version in the future.
    </para>
    
    <para>
      Templatization also makes localized versions of Bugzilla possible, 
      for the first time. It's possible to have Bugzilla's UI language 
      determined by the user's browser. More information is available in
      <xref linkend="template-http-accept"/>.
    </para>
    
    <section>
      <title>What to Edit</title>
      <para>
        The template directory structure is that there's a top level directory,
        <filename>template</filename>, which contains a directory for
        each installed localization. The default English templates are
        therefore in <filename>en</filename>. Underneath that, there
        is the <filename>default</filename> directory and optionally the 
        <filename>custom</filename> directory. The <filename>default</filename>
        directory contains all the templates shipped with Bugzilla, whereas
        the <filename>custom</filename> directory does not exist at first and
        must be created if you want to use it.
      </para>

      <para>
        There are two different ways of editing Bugzilla's templates,
        and which you use depends mainly on the method you plan to use to
        upgrade Bugzilla. 
        The first method of making customizations is to directly edit the
        templates in <filename>template/en/default</filename>. This is
        probably the best method for small changes if you are going to use
        the CVS method of upgrading, because if you then execute a
        <command>cvs update</command>, any template fixes will get
        automagically merged into your modified versions.
      </para>

      <para>
        If you use this method, your installation will break if CVS conflicts
        occur.
      </para>

      <para>
        The other method is to copy the templates to be modified into a 
        mirrored directory
        structure under <filename>template/en/custom</filename>.  The templates
        in this directory automatically override those in default.  
        This is the technique you
        need to use if you use the overwriting method of upgrade, because
        otherwise your changes will be lost.  This method is also better if
        you are using the CVS method of upgrading and are going to make major
        changes, because it is guaranteed that the contents of this directory
        will not be touched during an upgrade, and you can then decide whether
        to continue using your own templates, or make the effort to merge your
        changes into the new versions by hand.
      </para>

      <para>
        If you use this method, your installation may break if incompatible
        changes are made to the template interface.  If such changes are made
        they will be documented in the release notes, provided you are using a
        stable release of Bugzilla.  If you use using unstable code, you will
        need to deal with this one yourself, although if possible the changes
        will be mentioned before they occur in the deprecations section of the
        previous stable release's release notes.
      </para>

      <note>
        <para>
          Don't directly edit the compiled templates in 
          <filename class="directory">data/template/*</filename> - your
          changes will be lost when Template Toolkit recompiles them.
        </para>
      </note>

      <note>
        <para>It is recommended that you run <command>./checksetup.pl</command>
        after any template edits, especially if you've created a new file in
        the <filename class="directory">custom</filename> directory.
        </para>
      </note>
    </section>
    
    <section>
      <title>How To Edit Templates</title>
      
      <note>
        <para>
          If you are making template changes that you intend on submitting back
          for inclusion in standard Bugzilla, you should read the relevant
          sections of the 
          <ulink url="http://www.bugzilla.org/developerguide.html">Developers'
          Guide</ulink>.
        </para>
      </note>
      
      <para>
        The syntax of the Template Toolkit language is beyond the scope of
        this guide. It's reasonably easy to pick up by looking at the current 
        templates; or, you can read the manual, available on the
        <ulink url="http://www.template-toolkit.org">Template Toolkit home
        page</ulink>.
      </para>
      
      <para>
        One thing you should take particular care about is the need
        to properly HTML filter data that has been passed into the template.
        This means that if the data can possibly contain special HTML characters
        such as &lt;, and the data was not intended to be HTML, they need to be
        converted to entity form, ie &amp;lt;.  You use the 'html' filter in the
        Template Toolkit to do this.  If you forget, you may open up
        your installation to cross-site scripting attacks.
      </para>

      <para>
        Also note that Bugzilla adds a few filters of its own, that are not
        in standard Template Toolkit.  In particular, the 'url_quote' filter
        can convert characters that are illegal or have special meaning in URLs,
        such as &amp;, to the encoded form, ie %26.  This actually encodes most
        characters (but not the common ones such as letters and numbers and so
        on), including the HTML-special characters, so there's never a need to
        HTML filter afterwards.
      </para>
 
      <para>
        Editing templates is a good way of doing a "poor man's custom fields".
        For example, if you don't use the Status Whiteboard, but want to have
        a free-form text entry box for "Build Identifier", then you can just
        edit the templates to change the field labels. It's still be called
        status_whiteboard internally, but your users don't need to know that.
      </para>
      
    </section>
            
    
    <section>
      <title>Template Formats</title>
      
      <para>
        Some CGIs have the ability to use more than one template. For
        example, buglist.cgi can output bug lists as RDF or two
        different forms of HTML (complex and simple). (Try this out
        by appending <filename>&amp;format=simple</filename> to a buglist.cgi
        URL on your Bugzilla installation.) This
        mechanism, called template 'formats', is extensible.
      </para>
      
      <para>
        To see if a CGI supports multiple output formats, grep the
        CGI for "GetFormat". If it's not present, adding
        multiple format support isn't too hard - see how it's done in
        other CGIs, e.g. config.cgi.
      </para>
      
      <para>
        To make a new format template for a CGI which supports this, 
        open a current template for
        that CGI and take note of the INTERFACE comment (if present.) This 
        comment defines what variables are passed into this template. If 
        there isn't one, I'm afraid you'll have to read the template and
        the code to find out what information you get. 
      </para>     
  
      <para>
        Write your template in whatever markup or text style is appropriate.
      </para>
      
      <para>
        You now need to decide what content type you want your template
        served as. Open up the <filename>localconfig</filename> file and find the 
        <filename>$contenttypes</filename>
        variable. If your content type is not there, add it. Remember
        the three- or four-letter tag assigned to you content type. 
        This tag will be part of the template filename.
      </para>
      
      <para>
        Save the template as <filename>&lt;stubname&gt;-&lt;formatname&gt;.&lt;contenttypetag&gt;.tmpl</filename>. 
        Try out the template by calling the CGI as 
        <filename>&lt;cginame&gt;.cgi?format=&lt;formatname&gt;</filename> .
      </para>       
    </section>
    
    
    <section>
      <title>Particular Templates</title>
      
      <para>
        There are a few templates you may be particularly interested in
        customizing for your installation.
      </para>
      
      <para>
        <command>index.html.tmpl</command>:
        This is the Bugzilla front page.
      </para>      

      <para>
        <command>global/header.html.tmpl</command>:
        This defines the header that goes on all Bugzilla pages.
        The header includes the banner, which is what appears to users
        and is probably what you want to edit instead.  However the
        header also includes the HTML HEAD section, so you could for
        example add a stylesheet or META tag by editing the header.
      </para>

      <para>
        <command>global/banner.html.tmpl</command>:
        This contains the "banner", the part of the header that appears
        at the top of all Bugzilla pages.  The default banner is reasonably
        barren, so you'll probably want to customize this to give your
        installation a distinctive look and feel.  It is recommended you
        preserve the Bugzilla version number in some form so the version 
        you are running can be determined, and users know what docs to read.
      </para>

      <para>
        <command>global/footer.html.tmpl</command>:
        This defines the footer that goes on all Bugzilla pages.  Editing
        this is another way to quickly get a distinctive look and feel for
        your Bugzilla installation.
      </para>

      <para>
        <command>bug/create/user-message.html.tmpl</command>:
        This is a message that appears near the top of the bug reporting page.
        By modifying this, you can tell your users how they should report
        bugs.
      </para>

      <para>
        <command>bug/create/create.html.tmpl</command> and
        <command>bug/create/comment.txt.tmpl</command>:
        You may wish to get bug submitters to give certain bits of structured
        information, each in a separate input widget, for which there is not a
        field in the database. The bug entry system has been designed in an
        extensible fashion to enable you to define arbitrary fields and widgets,
        and have their values appear formatted in the initial
        Description, rather than in database fields. An example of this
        is the mozilla.org 
        <ulink url="http://bugzilla.mozilla.org/enter_bug.cgi?format=guided">guided 
        bug submission form</ulink>.
      </para>

      <para>
        To make this work, create a custom template for 
        <filename>enter_bug.cgi</filename> (the default template, on which you
        could base it, is <filename>create.html.tmpl</filename>),
        and either call it <filename>create.html.tmpl</filename> or use a format and
        call it <filename>create-&lt;formatname&gt;.html.tmpl</filename>.
        Put it in the <filename class="directory">custom/bug/create</filename>
        directory. In it, add widgets for each piece of information you'd like
        collected - such as a build number, or set of steps to reproduce.
      </para>

      <para>
        Then, create a template like 
        <filename>custom/bug/create/comment.txt.tmpl</filename>, also named
        after your format if you are using one, which
        references the form fields you have created. When a bug report is
        submitted, the initial comment attached to the bug report will be
        formatted according to the layout of this template.
      </para> 

      <para>
        For example, if your enter_bug template had a field
        <programlisting>&lt;input type="text" name="buildid" size="30"&gt;</programlisting>
        and then your comment.txt.tmpl had
        <programlisting>BuildID: [% form.buildid %]</programlisting>
        then
        <programlisting>BuildID: 20020303</programlisting>
        would appear in the initial checkin comment.
      </para>        
    </section>          
    

    <section id="template-http-accept">
      <title>Configuring Bugzilla to Detect the User's Language</title>

      <para>Bugzilla honours the user's Accept: HTTP header. You can install
      templates in other languages, and Bugzilla will pick the most appropriate
      according to a priority order defined by you. Many
      language templates can be obtained from <ulink 
      url="http://www.bugzilla.org/download.html#localizations"/>. Instructions
      for submitting new languages are also available from that location.
      </para>

      <para>After untarring the localizations (or creating your own) in the 
      <filename class="directory">BUGZILLA_ROOT/template</filename> directory,
      you must update the <option>languages</option> parameter to contain any
      localizations you'd like to permit. You may also wish to set the
      <option>defaultlanguage</option> parameter to something other than
      <quote>en</quote> if you don't want Engish to be the default language.
      </para>
    </section>
      
  </section>

  <section id="cust-hooks">
    <title>Template Hooks</title>
        
    <para>
      Template hooks are a way for extensions to Bugzilla to insert code
      into the standard Bugzilla templates without modifying the template files
      themselves.  The hooks mechanism defines a consistent API for extending
      the standard templates in a way that cleanly separates standard code
      from extension code.  Hooks reduce merge conflicts and make it easier
      to write extensions that work across multiple versions of Bugzilla,
      making upgrading a Bugzilla installation with installed extensions easier.
    </para>

    <para>
      A template hook is just a named place in a standard template file
      where extension template files for that hook get processed.  Each hook
      has a corresponding directory in the Bugzilla directory tree.  Hooking an
      extension template to a hook is as simple as putting the extension file
      into the hook's directory.  When Bugzilla processes the standard template
      and reaches the hook, it will process all extension templates in the
      hook's directory. The hooks themselves can be added into any standard
      template upon request by extension authors.
    </para>
    
    <para>
      To use hooks to extend a Bugzilla template, first make sure there is
      a hook at the appropriate place within the template you want to extend. 
      Hooks appear in the standard Bugzilla templates as a single directive
      in the format
      <literal role="code">[% Hook.process("<varname>name</varname>") %]</literal>,
      where <varname>name</varname> is the unique (within that template)
      name of the hook.
    </para>

    <para>
      If you aren't sure which template you want to extend or just want
      to browse the available hooks, either use your favorite multi-file search
      tool (e.g. <command>grep</command>) to search the standard templates
      for occurrences of <methodname>Hook.process</methodname> or browse
      the directory tree in
      <filename>BUGZILLA_ROOT/template/en/extension/hook/</filename>,
      which contains a directory for each hook in the following location:
    </para>

    <para>
      <filename>BUGZILLA_ROOT/template/en/extension/hook/PATH_TO_STANDARD_TEMPLATE/STANDARD_TEMPLATE_NAME/HOOK_NAME/</filename>
    </para>

    <para>
      If there is no hook at the appropriate place within the Bugzilla template
      you want to extend,
      <ulink url="http://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&amp;component=User%20Interface">file
      a bug requesting one</ulink>, specifying:
    </para>

    <simplelist>
      <member>the template for which you are requesting a hook;</member>
      <member>
        where in the template you would like the hook to be placed
        (line number/position for latest version of template in CVS
        or description of location);
      </member>
      <member>the purpose of the hook;</member>
      <member>a link to information about your extension, if any.</member>
    </simplelist>

    <para>
      The Bugzilla reviewers will promptly review each hook request,
      name the hook, add it to the template, check the new version
      of the template into CVS, and create the corresponding directory in
      <filename>BUGZILLA_ROOT/template/en/extension/hook/</filename>.
    </para>

    <para>
      You may optionally attach a patch to the bug which implements the hook
      and check it in yourself after receiving approval from a Bugzilla
      reviewer.  The developers may suggest changes to the location of the
      hook based on their analysis of your needs or so the hook can satisfy
      the needs of multiple extensions, but the process of getting hooks
      approved and checked in is not as stringent as the process for general
      changes to Bugzilla, and any extension, whether released or still in
      development, can have hooks added to meet their needs.
    </para>

    <para>
      After making sure the hook you need exists (or getting it added if not),
      add your extension template to the directory within the Bugzilla
      directory tree corresponding to the hook. 
    </para>
    
    <para>
      That's it!  Now, when the standard template containing the hook
      is processed, your extension template will be processed at the point 
      where the hook appears.
    </para>

    <para>
      For example, let's say you have an extension named Projman that adds
      project management capabilities to Bugzilla.  Projman has an
      administration interface <filename>edit-projects.cgi</filename>, 
      and you want to add a link to it into the navigation bar at the bottom
      of every Bugzilla page for those users who are authorized
      to administer projects.
    </para>

    <para>
      The navigation bar is generated by the template file
      <filename>useful-links.html.tmpl</filename>, which is located in
      the <filename>global/</filename> subdirectory on the standard Bugzilla 
      template path
      <filename>BUGZILLA_ROOT/template/en/default/</filename>.
      Looking in <filename>useful-links.html.tmpl</filename>, you find
      the following hook at the end of the list of standard Bugzilla
      administration links:
    </para>

    <programlisting><![CDATA[...
    [% ', <a href="editkeywords.cgi">keywords</a>' 
                                              IF user.groups.editkeywords %]
    [% Hook.process("edit") %]
...]]></programlisting>

    <para>
      The corresponding directory for this hook is
      <filename>BUGZILLA_ROOT/template/en/extension/hook/global/useful-links.html.tmpl/edit/</filename>.
    </para>

    <para>
      You put a template named
      <filename>projman-edit-projects.html.tmpl</filename>
      into that directory with the following content:
    </para>

    <programlisting><![CDATA[...[% ', <a href="edit-projects.cgi">projects</a>' IF user.groups.projman_admins %]]]></programlisting>

    <para>
      Voila!  The link now appears after the other administration links in the
      navigation bar for users in the <literal>projman_admins</literal> group.
    </para>

    <para>
      Notes:
    </para>

    <itemizedlist>
      <listitem>
        <para>
          You may want to prefix your extension template names
          with the name of your extension, e.g. 
          <filename>projman-foo.html.tmpl</filename>, 
          so they do not conflict with the names of templates installed by
          other extensions.
        </para>
      </listitem>

      <listitem>
        <para>
          If your extension includes entirely new templates in addition to
          extensions of standard templates, it should install those new
          templates into an extension-specific subdirectory of the
          <filename>BUGZILLA_ROOT/template/en/extension/</filename> 
          directory.  The <filename>extension/</filename> directory, like the 
          <filename>default/</filename> and <filename>custom/</filename>
          directories, is part of the template search path, so putting templates
          there enables them to be found by the template processor.
        </para>

        <para>
          The template processor looks for templates first in the
          <filename>custom/</filename> directory (i.e. templates added by the 
          specific installation), then in the <filename>extension/</filename> 
          directory (i.e. templates added by extensions), and finally in the
          <filename>default/</filename> directory (i.e. the standard Bugzilla 
          templates).  Thus extension templates can override standard templates,
          but installation-specific templates override both.
        </para>

        <para>
          Note that overriding standard templates with extension templates
          gives you great power but also makes upgrading an installation harder.
          As with custom templates,  we recommend using this functionality
          sparingly and only when absolutely necessary.
        </para>
      </listitem>

      <listitem>
        <para>
          Installation customizers can also take advantage of hooks when adding
          code to a Bugzilla template.  To do so, create directories in
          <filename>BUGZILLA_ROOT/template/en/custom/hook/</filename>
          equivalent to the directories in
          <filename>BUGZILLA_ROOT/template/en/extension/hook/</filename>          
          for the hooks you want to use, then place your customization templates
          into those directories.
        </para>

        <para>
          Obviously this method of customizing Bugzilla only lets you add code
          to the standard templates; you cannot change the existing code.
          Nevertheless, for those customizations that only add code, this method
          can reduce conflicts when merging changes, making upgrading
          your customized Bugzilla installation easier.
        </para>
      </listitem>
    </itemizedlist>    
  </section>

  <section id="cust-change-permissions">
    <title>Customizing Who Can Change What</title>
    
    <warning>
      <para>
        This feature should be considered experimental; the Bugzilla code you
        will be changing is not stable, and could change or move between 
        versions. Be aware that if you make modifications as outlined here, 
        you may have
        to re-make them or port them if Bugzilla changes internally between
        versions, and you upgrade.
      </para>
    </warning>
       
    <para>
      Companies often have rules about which employees, or classes of employees,
      are allowed to change certain things in the bug system. For example, 
      only the bug's designated QA Contact may be allowed to VERIFY the bug.
      Bugzilla has been
      designed to make it easy for you to write your own custom rules to define
      who is allowed to make what sorts of value transition.
    </para>
    
    <para>
      For maximum flexibility, customizing this means editing Bugzilla's Perl 
      code. This gives the administrator complete control over exactly who is
      allowed to do what. The relevant function is called 
      <filename>CheckCanChangeField()</filename>,
      and is found in <filename>process_bug.cgi</filename> in your 
      Bugzilla directory. If you open that file and grep for 
      "sub CheckCanChangeField", you'll find it.
    </para>
    
    <para>
      This function has been carefully commented to allow you to see exactly
      how it works, and give you an idea of how to make changes to it. Certain
      marked sections should not be changed - these are the "plumbing" which
      makes the rest of the function work. In between those sections, you'll
      find snippets of code like:
      <programlisting>    # Allow the owner to change anything.
    if ($ownerid eq $whoid) {
        return 1;
    }</programlisting>
      It's fairly obvious what this piece of code does.
    </para>      
      
    <para>
      So, how does one go about changing this function? Well, simple changes
      can be made just be removing pieces - for example, if you wanted to 
      prevent any user adding a comment to a bug, just remove the lines marked
      "Allow anyone to change comments." And if you want the reporter to have
      no special rights on bugs they have filed, just remove the entire section
      which refers to him.
    </para>
    
    <para>
      More complex customizations are not much harder. Basically, you add
      a check in the right place in the function, i.e. after all the variables
      you are using have been set up. So, don't look at $ownerid before 
      $ownerid has been obtained from the database. You can either add a
      positive check, which returns 1 (allow) if certain conditions are true,
      or a negative check, which returns 0 (deny.) E.g.:
      <programlisting>    if ($field eq "qacontact") {
        if (Bugzilla->user->groups("quality_assurance")) {
            return 1;
        } 
        else {
            return 0;
        }
    }</programlisting>
      This says that only users in the group "quality_assurance" can change
      the QA Contact field of a bug. Getting more weird:
      <programlisting>    if (($field eq "priority") &&
        (Bugzilla->user->email =~ /.*\@example\.com$/))
    {
        if ($oldvalue eq "P1") {
            return 1;
        } 
        else {
            return 0;
        }
    }</programlisting>
      This says that if the user is trying to change the priority field,
      and their email address is @example.com, they can only do so if the
      old value of the field was "P1". Not very useful, but illustrative.
    </para>
    
    <para>
      For a list of possible field names, look in 
      <filename>data/versioncache</filename> for the list called 
      <filename>@::log_columns</filename>. If you need help writing custom
      rules for your organization, ask in the newsgroup.
    </para>    
  </section>   
  
  <section id="dbmodify">
      <title>Modifying Your Running System</title>

      <para>Bugzilla optimizes database lookups by storing all relatively
      static information in the 
      <filename>versioncache</filename> file, located in the 
      <filename class="directory">data/</filename>
      subdirectory under your installation directory.</para>

      <para>If you make a change to the structural data in your database (the
      versions table for example), or to the 
      <quote>constants</quote>

      encoded in <filename>defparams.pl</filename>, you will need to remove 
      the cached content from the data directory (by doing a 
      <quote>rm data/versioncache</quote>

      ), or your changes won't show up.</para>

      <para> <filename>versioncache</filename> 
      gets automatically regenerated whenever it's more than
      an hour old, so Bugzilla will eventually notice your changes by itself,
      but generally you want it to notice right away, so that you can test
      things.</para>
    </section>

  <section id="dbdoc">
    <title>MySQL Bugzilla Database Introduction</title>

    <para>This information comes straight from my life. I was forced to learn
    how Bugzilla organizes database because of nitpicky requests from users
    for tiny changes in wording, rather than having people re-educate
    themselves or figure out how to work our procedures around the tool. It
    sucks, but it can and will happen to you, so learn how the schema works
    and deal with it when it comes.</para>

    <para>So, here you are with your brand-new installation of Bugzilla.
    You've got MySQL set up, Apache working right, Perl DBI and DBD talking
    to the database flawlessly. Maybe you've even entered a few test bugs to
    make sure email's working; people seem to be notified of new bugs and
    changes, and you can enter and edit bugs to your heart's content. Perhaps
    you've gone through the trouble of setting up a gateway for people to
    submit bugs to your database via email, have had a few people test it,
    and received rave reviews from your beta testers.</para>

    <para>What's the next thing you do? Outline a training strategy for your
    development team, of course, and bring them up to speed on the new tool
    you've labored over for hours.</para>

    <para>Your first training session starts off very well! You have a
    captive audience which seems enraptured by the efficiency embodied in
    this thing called "Bugzilla". You are caught up describing the nifty
    features, how people can save favorite queries in the database, set them
    up as headers and footers on their pages, customize their layouts,
    generate reports, track status with greater efficiency than ever before,
    leap tall buildings with a single bound and rescue Jane from the clutches
    of Certain Death!</para>

    <para>But Certain Death speaks up -- a tiny voice, from the dark corners
    of the conference room. "I have a concern," the voice hisses from the