package mygtk2; use diagnostics; use strict; our @ISA = qw(Exporter); our @EXPORT = qw(gtknew gtkset gtkadd gtkval_register gtkval_modify); use c; use log; use common; use Gtk2; use Gtk2::Gdk::Keysyms; unless ($::no_ugtk_init) { !check_for_xserver() and print("Cannot be run in console mode.\n"), c::_exit(0); $::one_message_has_been_translated and warn("N() was called from $::one_message_has_been_translated BEFORE gtk2 initialisation, replace it with a N_() AND a translate() later.\n"), c::_exit(1); Gtk2->init; Locale::gettext::bind_textdomain_codeset($_, 'UTF8') foreach 'libDrakX', if_(!$::isInstall, 'libDrakX-standalone'), 'drakx-net', 'drakx-kbd-mouse-x11', # shared translation @::textdomains; } Gtk2->croak_execeptions if (!$::no_ugtk_init || $::isInstall) && 0.95 < $Gtk2::VERSION; sub gtknew { my $class = shift; if (@_ % 2 != 0) { internal_error("gtknew $class: bad options @_"); } if (my $r = find { ref $_->[0] } group_by2(@_)) { internal_error("gtknew $class: $r should be a string in @_"); } my %opts = @_; _gtk(undef, $class, 'gtknew', \%opts); } sub gtkset { my $w = shift; my $class = ref($w); if (@_ % 2 != 0) { internal_error("gtkset $class: bad options @_"); } if (my $r = find { ref $_->[0] } group_by2(@_)) { internal_error("gtkset $class: $r should be a string in @_"); } my %opts = @_; $class =~ s/^(Gtk2|Gtk2::Gdk|mygtk2)::// or internal_error("gtkset unknown class $class"); _gtk($w, $class, 'gtkset', \%opts); } sub gtkadd { my $w = shift; my $class = ref($w); if (@_ % 2 != 0) { internal_error("gtkadd $class: bad options @_"); } if (my $r = find { ref $_->[0] } group_by2(@_)) { internal_error("gtkadd $class: $r should be a string in @_"); } my %opts = @_; $class =~ s/^(Gtk2|Gtk2::Gdk|mygtk2)::// or internal_error("gtkadd unknown class $class"); _gtk($w, $class, 'gtkadd', \%opts); } my %refs; sub gtkval_register { my ($w, $ref, $sub) = @_; push @{$w->{_ref}}, $ref; $w->signal_connect(destroy => sub { @{$refs{$ref}} = grep { $_->[1] != $w } @{$refs{$ref}}; delete $refs{$ref} if !@{$refs{$ref}}; }); push @{$refs{$ref}}, [ $sub, $w ]; } sub gtkval_modify { my ($ref, $val, @to_skip) = @_; my $prev = '' . $ref; $$ref = $val; if ($prev ne '' . $ref) { internal_error(); } foreach (@{$refs{$ref} || []}) { my ($f, @para) = @$_; $f->(@para) if !member($f, @to_skip); } } my $global_tooltips; sub _gtk { my ($w, $class, $action, $opts) = @_; if (my $f = $mygtk2::{"_gtk__$class"}) { $w = $f->($w, $opts, $class, $action); } else { internal_error("$action $class: unknown class"); } $w->set_size_request(delete $opts->{width} || -1, delete $opts->{height} || -1) if exists $opts->{width} || exists $opts->{height}; if (my $position = delete $opts->{position}) { $w->move($position->[0], $position->[1]); } $w->set_name(delete $opts->{widget_name}) if exists $opts->{widget_name}; $w->can_focus(delete $opts->{can_focus}) if exists $opts->{can_focus}; $w->can_default(delete $opts->{can_default}) if exists $opts->{can_default}; $w->grab_focus if delete $opts->{grab_focus}; $w->set_padding(@{delete $opts->{padding}}) if exists $opts->{padding}; $w->set_sensitive(delete $opts->{sensitive}) if exists $opts->{sensitive}; (delete $opts->{size_group})->add_widget($w) if $opts->{size_group}; if (my $tip = delete $opts->{tip}) { $global_tooltips ||= Gtk2::Tooltips->new; $global_tooltips->set_tip($w, $tip); } #- WARNING: hide_ref and show_ref are not effective until you gtkval_modify the ref if (my $hide_ref = delete $opts->{hide_ref}) { gtkval_register($w, $hide_ref, sub { $$hide_ref ? $w->hide : $w->show }); } elsif (my $show_ref = delete $opts->{show_ref}) { gtkval_register($w, $show_ref, sub { $$show_ref ? $w->show : $w->hide }); } if (%$opts && !$opts->{allow_unknown_options}) { internal_error("$action $class: unknown option(s) " . join(', ', keys %$opts)); } $w; } sub _gtk__Button { &_gtk_any_Button } sub _gtk__ToggleButton { &_gtk_any_Button } sub _gtk__CheckButton { &_gtk_any_Button } sub _gtk__RadioButton { &_gtk_any_Button } sub _gtk_any_Button { my ($w, $opts, $class) = @_; if (!$w) { my @radio_options; if ($class eq 'RadioButton') { @radio_options = delete $opts->{group}; } $w = $opts->{child} ? "Gtk2::$class"->new(@radio_options) : delete $opts->{mnemonic} ? "Gtk2::$class"->new_with_mnemonic(@radio_options, delete $opts->{text} || '') : $opts->{text} ? "Gtk2::$class"->new_with_label(@radio_options, delete $opts->{text} || '') : "Gtk2::$class"->new(@radio_options); $w->{format} = delete $opts->{format} if exists $opts->{format}; } if (my $widget = delete $opts->{child}) { $w->add($widget); $widget->show; } $w->set_image(delete $opts->{image}) if exists $opts->{image}; $w->set_relief(delete $opts->{relief}) if exists $opts->{relief}; if (my $text_ref = delete $opts->{text_ref}) { my $set = sub { eval { $w->set_label(may_apply($w->{format}, $$text_ref)) }; }; gtkval_register($w, $text_ref, $set); $set->(); } elsif (exists $opts->{text}) { $w->set_label(delete $opts->{text}); } if ($class eq 'Button') { $w->signal_connect(clicked => delete $opts->{clicked}) if exists $opts->{clicked}; } else { if (my $active_ref = delete $opts->{active_ref}) { my $set = sub { $w->set_active($$active_ref) }; $w->signal_connect(toggled => sub { gtkval_modify($active_ref, $w->get_active, $set); }); gtkval_register($w, $active_ref, $set); gtkval_register($w, $active_ref, delete $opts->{toggled}) if exists $opts->{toggled}; $set->(); } else { $w->set_active(delete $opts->{active}) if exists $opts->{active}; $w->signal_connect(toggled => delete $opts->{toggled}) if exists $opts->{toggled}; } } $w; } sub _gtk__CheckMenuItem { my ($w, $opts, $class) = @_; if (!$w) { add2hash_($opts, { mnemonic => 1 }); $w = $opts->{image} || !exists $opts->{text} ? "Gtk2::$class"->new : delete $opts->{mnemonic} ? "Gtk2::$class"->new_with_label(delete $opts->{text}) : "Gtk2::$class"->new_with_mnemonic(delete $opts->{text}); } $w->set_active(delete $opts->{active}) if exists $opts->{active}; $w->signal_connect(toggled => delete $opts->{toggled}) if exists $opts->{toggled}; $w; } sub _gtk___SpinButton { my ($w, $opts) = @_; if (!$w) { $opts->{adjustment} ||= do { add2hash_($opts, { step_increment => 1, page_increment => 5, page_size => 1, value => delete $opts->{lower} }); Gtk2::Adjustment->new(delete $opts->{value}, delete $opts->{lower}, delete $opts->{upper}, delete $opts->{step_increment}, delete $opts->{page_increment}, delete $opts->{page_size}); }; $w = Gtk2::SpinButton->new(delete $opts->{adjustment}, delete $opts->{climb_rate} || 0, delete $opts->{digits} || 0); } $w->signal_connect(value_changed => delete $opts->{value_changed}) if exists $opts->{value_changed}; $w; } sub _gtk__HScale { my ($w, $opts) = @_; if (!$w) { $opts->{adjustment} ||= do { add2hash_($opts, { step_increment => 1, page_increment => 5, page_size => 1, value => delete $opts->{lower} }); Gtk2::Adjustment->new(delete $opts->{value}, delete $opts->{lower}, (delete $opts->{upper}) + 1, delete $opts->{step_increment}, delete $opts->{page_increment}, delete $opts->{page_size}); }; $w = Gtk2::HScale->new(delete $opts->{adjustment}); } $w->signal_connect(value_changed => delete $opts->{value_changed}) if exists $opts->{value_changed}; $w; } sub _gtk__ProgressBar { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::ProgressBar->new; } if (my $fraction_ref = delete $opts->{fraction_ref}) { my $set = sub { $w->set_fraction($$fraction_ref) }; gtkval_register($w, $fraction_ref, $set); $set->(); } elsif (exists $opts->{fraction}) { $w->set_fraction(delete $opts->{fraction}); } $w; } sub _gtk__VSeparator { &_gtk_any_simple } sub _gtk__HSeparator { &_gtk_any_simple } sub _gtk__Calendar { &_gtk_any_simple } sub _gtk__DrawingArea { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::DrawingArea->new; } $w->signal_connect(expose_event => delete $opts->{expose_event}) if exists $opts->{expose_event}; $w; } sub _gtk__Pixbuf { my ($w, $opts) = @_; if (!$w) { my $name = delete $opts->{file} or internal_error("missing file"); my $file = _find_imgfile($name) or internal_error("can not find image $name"); if (my $size = delete $opts->{size}) { $w = Gtk2::Gdk::Pixbuf->new_from_file_at_scale($file, $size, $size, 1); } else { $w = Gtk2::Gdk::Pixbuf->new_from_file($file); } } $w; } # Image_using_pixmap is rendered using DITHER_MAX which is much better on 16bpp displays sub _gtk__Image_using_pixmap { &_gtk__Image } sub _gtk__Image { my ($w, $opts, $class) = @_; if (!$w) { $w = Gtk2::Image->new; $w->{format} = delete $opts->{format} if exists $opts->{format}; $w->{set_from_file} = $class =~ /using_pixmap/ ? sub { my ($w, $file) = @_; my $pixmap = mygtk2::pixmap_from_pixbuf($w, gtknew('Pixbuf', file => $file)); $w->set_from_pixmap($pixmap, undef); } : sub { my ($w, $file, $o_size) = @_; if ($o_size) { my $pixbuf = gtknew('Pixbuf', file => $file, size => $o_size); $w->set_from_pixbuf($pixbuf); } else { $w->set_from_file($file); } }; } if (my $name = delete $opts->{file}) { my $file = _find_imgfile(may_apply($w->{format}, $name)) or internal_error("can not find image $name"); $w->{set_from_file}->($w, $file, delete $opts->{size}); } elsif (my $file_ref = delete $opts->{file_ref}) { my $set = sub { my $file = _find_imgfile(may_apply($w->{format}, $$file_ref)) or internal_error("can not find image $$file_ref"); $w->{set_from_file}->($w, $file, delete $opts->{size}); }; gtkval_register($w, $file_ref, $set); $set->() if $$file_ref; } $w; } sub _gtk__WrappedLabel { my ($w, $opts) = @_; $opts->{line_wrap} = 1; _gtk__Label($w, $opts); } sub _gtk__Label_Left { my ($w, $opts) = @_; $opts->{alignment} ||= [ 0, 0 ]; $opts->{padding} = [ 20, 0 ]; _gtk__Label($w, $opts); } sub _gtk__Label { my ($w, $opts) = @_; if ($w) { $w->set_text(delete $opts->{text}) if exists $opts->{text}; } else { $w = exists $opts->{text} ? Gtk2::Label->new(delete $opts->{text}) : Gtk2::Label->new; $w->set_ellipsize(delete $opts->{ellipsize}) if exists $opts->{ellipsize}; $w->set_justify(delete $opts->{justify}) if exists $opts->{justify}; $w->set_line_wrap(delete $opts->{line_wrap}) if exists $opts->{line_wrap}; $w->set_alignment(@{delete $opts->{alignment}}) if exists $opts->{alignment}; $w->modify_font(Gtk2::Pango::FontDescription->from_string(delete $opts->{font})) if exists $opts->{font}; } if (my $text_ref = delete $opts->{text_ref}) { my $set = sub { $w->set_text($$text_ref) }; gtkval_register($w, $text_ref, $set); $set->(); } if (my $t = delete $opts->{text_markup}) { $w->set_markup($t); if ($w->get_text eq '') { log::l("invalid markup in $t. not using the markup"); $w->set_text($t); } } $w; } sub title1_to_markup { my ($label) = @_; '<b><big>' . $label . '</big></b>'; } sub _gtk__Title1 { my ($w, $opts) = @_; $opts ||= {}; $opts->{text_markup} = '<b><big>' . delete($opts->{label}) . '</big></b>'; _gtk__Label($w, $opts); } sub _gtk__Title2 { my ($w, $opts) = @_; $opts ||= {}; $opts->{alignment} = [ 0, 0 ]; _gtk__Title1($w, $opts); } sub _gtk__Entry { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::Entry->new; $w->set_editable(delete $opts->{editable}) if exists $opts->{editable}; } $w->set_text(delete $opts->{text}) if exists $opts->{text}; $w->signal_connect(key_press_event => delete $opts->{key_press_event}) if exists $opts->{key_press_event}; if (my $text_ref = delete $opts->{text_ref}) { my $set = sub { $w->set_text($$text_ref) }; gtkval_register($w, $text_ref, $set); $set->(); } $w; } sub _gtk__TextView { my ($w, $opts, $_class, $action) = @_; if (!$w) { $w = Gtk2::TextView->new; $w->set_editable(delete $opts->{editable}) if exists $opts->{editable}; $w->set_wrap_mode(delete $opts->{wrap_mode}) if exists $opts->{wrap_mode}; $w->set_cursor_visible(delete $opts->{cursor_visible}) if exists $opts->{cursor_visible}; } _text_insert($w, delete $opts->{text}, append => $action eq 'gtkadd') if exists $opts->{text}; $w; } sub _gtk__ComboBox { my ($w, $opts, $_class, $action) = @_; if (!$w) { $w = Gtk2::ComboBox->new_text; $w->{format} = delete $opts->{format} if exists $opts->{format}; } my $set_list = sub { $w->{formatted_list} = $w->{format} ? [ map { $w->{format}($_) } @{$w->{list}} ] : $w->{list}; $w->get_model->clear; $w->{strings} = $w->{formatted_list}; # used by Gtk2::ComboBox wrappers such as get_text() in ugtk2 $w->append_text($_) foreach @{$w->{formatted_list}}; }; if (my $list_ref = delete $opts->{list_ref}) { !$opts->{list} or internal_error("both list and list_ref"); my $set = sub { $w->{list} = $$list_ref; $set_list->(); }; gtkval_register($w, $list_ref, $set); $set->(); } elsif (exists $opts->{list}) { $w->{list} = delete $opts->{list}; $set_list->(); } if ($action eq 'gtknew') { if (my $text_ref = delete $opts->{text_ref}) { my $set = sub { my $val = may_apply($w->{format}, $$text_ref); eval { $w->set_active(find_index { $_ eq $val } @{$w->{formatted_list}}) }; }; $w->signal_connect(changed => sub { gtkval_modify($text_ref, $w->{list}[$w->get_active], $set); }); gtkval_register($w, $text_ref, $set); gtkval_register($w, $text_ref, delete $opts->{changed}) if exists $opts->{changed}; $set->(); } else { my $val = delete $opts->{text}; eval { $w->set_active(find_index { $_ eq $val } @{$w->{formatted_list}}) } if defined $val; $w->signal_connect(changed => delete $opts->{changed}) if exists $opts->{changed}; } } $w; } sub _gtk__ScrolledWindow { my ($w, $opts, $_class, $action) = @_; if (!$w) { $w = Gtk2::ScrolledWindow->new(undef, undef); $w->set_policy(delete $opts->{h_policy} || 'automatic', delete $opts->{v_policy} || 'automatic'); } my $faked_w = $w; if (my $child = delete $opts->{child}) { if (member(ref($child), qw(Gtk2::Layout Gtk2::Html2::View Gtk2::SimpleList Gtk2::SourceView::View Gtk2::Text Gtk2::TextView Gtk2::TreeView))) { $w->add($child); } else { $w->add_with_viewport($child); } $child->set_focus_vadjustment($w->get_vadjustment) if $child->can('set_focus_vadjustment'); $child->set_left_margin(6) if ref($child) =~ /Gtk2::TextView/; $child->show; $w->child->set_shadow_type(delete $opts->{shadow_type}) if exists $opts->{shadow_type}; if (ref($child) eq 'Gtk2::TextView' && delete $opts->{to_bottom}) { $child->{to_bottom} = _allow_scroll_TextView_to_bottom($w, $child); } if ($action eq 'gtknew' && ref($child) =~ /Gtk2::TextView|Gtk2::TreeView/) { $faked_w = gtknew('Frame', shadow_type => 'in', child => $w); } } $faked_w; } sub _gtk__Frame { my ($w, $opts) = @_; if ($w) { $w->set_label(delete $opts->{text}) if exists $opts->{text}; } else { $w = Gtk2::Frame->new(delete $opts->{text}); $w->set_border_width(delete $opts->{border_width}) if exists $opts->{border_width}; $w->set_shadow_type(delete $opts->{shadow_type}) if exists $opts->{shadow_type}; } if (my $child = delete $opts->{child}) { $w->add($child); $child->show; } $w; } sub _gtk__Expander { my ($w, $opts) = @_; if ($w) { $w->set_label(delete $opts->{text}) if exists $opts->{text}; } else { $w = Gtk2::Expander->new(delete $opts->{text}); } $w->signal_connect(activate => delete $opts->{activate}) if exists $opts->{activate}; if (my $child = delete $opts->{child}) { $w->add($child); $child->show; } $w; } sub _gtk__Window { &_gtk_any_Window } sub _gtk__Dialog { &_gtk_any_Window } sub _gtk__Plug { &_gtk_any_Window } sub _gtk_any_Window { my ($w, $opts, $class) = @_; if (!$w) { if ($class eq 'Window') { $w = "Gtk2::$class"->new(delete $opts->{type} || 'toplevel'); } elsif ($class eq 'Plug') { $opts->{socket_id} or internal_error("can not create a Plug without a socket_id"); $w = "Gtk2::$class"->new(delete $opts->{socket_id}); } else { $w = "Gtk2::$class"->new; } $w->set_modal(1) if exists $opts->{transient_for}; $w->set_modal(delete $opts->{modal}) if exists $opts->{modal}; $w->set_transient_for(delete $opts->{transient_for}) if exists $opts->{transient_for}; $w->set_border_width(delete $opts->{border_width}) if exists $opts->{border_width}; $w->set_shadow_type(delete $opts->{shadow_type}) if exists $opts->{shadow_type}; $w->set_position(delete $opts->{position_policy}) if exists $opts->{position_policy}; $w->set_default_size(delete $opts->{default_width} || -1, delete $opts->{default_height} || -1) if exists $opts->{default_width} || exists $opts->{default_height}; my $icon_no_error = $opts->{icon_no_error}; if (my $name = delete $opts->{icon} || delete $opts->{icon_no_error}) { if (my $f = _find_imgfile($name)) { $w->set_icon(gtknew('Pixbuf', file => $f)); } elsif (!$icon_no_error) { internal_error("can not find $name"); } } } $w->set_title(delete $opts->{title}) if exists $opts->{title}; if (my $child = delete $opts->{child}) { $w->add($child); $child->show; } $w; } sub _gtk__MagicWindow { my ($w, $opts) = @_; my $pop_it = delete $opts->{pop_it} || !$::isWizard && !$::isEmbedded || $::WizardTable && do { #- do not take into account the wizard banner any { !$_->isa('Gtk2::DrawingArea') && $_->visible } $::WizardTable->get_children; }; my $sub_child = delete $opts->{child}; my $provided_banner = delete $opts->{banner}; if ($pop_it && $provided_banner) { $sub_child = gtknew('VBox', children => [ 0, $provided_banner, if_($sub_child, 1, $sub_child) ]); } else { $sub_child ||= gtknew('VBox'); } if ($pop_it) { $opts->{child} = $::isInstall ? gtknew('Frame', shadow_type => 'out', child => gtknew('Frame', shadow_type => 'none', border_width => 3, child => $sub_child)) : $sub_child; $w = _create_Window($opts); } else { if (!$::WizardWindow) { my $banner; if (!$::isEmbedded && !$::isInstall && $::Wizard_title) { if (_find_imgfile($opts->{icon_no_error})) { $banner = Gtk2::Banner->new($opts->{icon_no_error}, $::Wizard_title); } else { log::l("ERROR: missing wizard banner $opts->{icon_no_error}"); } } $::WizardTable = gtknew('VBox', if_($banner, children_tight => [ $banner ])); if ($::isEmbedded) { add2hash($opts, { socket_id => $::XID, child => $::WizardTable, }); delete $opts->{no_Window_Manager}; $::Plug = $::WizardWindow = _gtk(undef, 'Plug', 'gtknew', $opts); sync($::WizardWindow); } else { add2hash($opts, { child => gtknew('Frame', shadow_type => 'out', child => $::WizardTable), }); $::WizardWindow = _create_Window($opts); } } else { %$opts = (); } set_main_window_size($::WizardWindow); $w = $::WizardWindow; gtkadd($::WizardTable, children_tight => [ $provided_banner ]) if $provided_banner; gtkadd($::WizardTable, children_loose => [ $sub_child ]); } bless { real_window => $w, child => $sub_child, pop_it => $pop_it, if_($provided_banner, banner => $provided_banner), }, 'mygtk2::MagicWindow'; } # A standard About dialog. Used with: # my $w = gtknew('AboutDialog', ...); # $w->show_all; # $w->run; sub _gtk__AboutDialog { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::AboutDialog->new; $w->signal_connect(response => sub { $_[0]->destroy }); $w->set_name(delete $opts->{name}) if exists $opts->{name}; $w->set_version(delete $opts->{version}) if exists $opts->{version}; $w->set_icon(gtknew('Pixbuf', file => delete $opts->{icon})) if exists $opts->{icon}; $w->set_logo(gtknew('Pixbuf', file => delete $opts->{logo})) if exists $opts->{logo}; $w->set_copyright(delete $opts->{copyright}) if exists $opts->{copyright}; $w->set_url_hook(sub { my (undef, $url) = @_; run_program::raw({ detach => 1 }, 'www-browser', $url); }); $w->set_email_hook(sub { my (undef, $url) = @_; run_program::raw({ detach => 1 }, 'www-browser', $url); }); if (my $url = delete $opts->{website}) { $url =~ s/^https:/http:/; # Gtk2::About doesn't like "https://..." like URLs $w->set_website($url); } $w->set_license(delete $opts->{license}) if exists $opts->{license}; $w->set_wrap_license(delete $opts->{wrap_license}) if exists $opts->{wrap_license}; $w->set_comments(delete $opts->{comments}) if exists $opts->{comments}; $w->set_website_label(delete $opts->{website_label}) if exists $opts->{website_label}; $w->set_authors(delete $opts->{authors}) if exists $opts->{authors}; $w->set_documenters(delete $opts->{documenters}) if exists $opts->{documenters}; $w->set_translator_credits(delete $opts->{translator_credits}) if exists $opts->{translator_credits}; $w->set_artists(delete $opts->{artists}) if exists $opts->{artists}; $w->set_modal(delete $opts->{modal}) if exists $opts->{modal}; $w->set_transient_for(delete $opts->{transient_for}) if exists $opts->{transient_for}; $w->set_position(delete $opts->{position_policy}) if exists $opts->{position_policy}; } $w; } sub _gtk__FileSelection { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::FileSelection->new(delete $opts->{title} || ''); gtkset($w->ok_button, %{delete $opts->{ok_button}}) if exists $opts->{ok_button}; gtkset($w->cancel_button, %{delete $opts->{cancel_button}}) if exists $opts->{cancel_button}; } $w; } sub _gtk__FileChooser { my ($w, $opts) = @_; #- no nice way to have a {file_ref} on a FileChooser since selection_changed only works for browsing, not file/folder creation if (!$w) { my $action = delete $opts->{action} || internal_error("missing action for FileChooser"); $w = Gtk2::FileChooserWidget->new($action); my $file = $opts->{file} && delete $opts->{file}; if (my $dir = delete $opts->{directory} || $file && dirname($file)) { $w->set_current_folder($dir); } if ($file) { if ($action =~ /save|create/) { $w->set_current_name(basename($file)); } else { $w->set_filename($file); } } } $w; } sub _gtk__VPaned { &_gtk_any_Paned } sub _gtk__HPaned { &_gtk_any_Paned } sub _gtk_any_Paned { my ($w, $opts, $class, $action) = @_; if (!$w) { $w = "Gtk2::$class"->new; $w->set_border_width(delete $opts->{border_width}) if exists $opts->{border_width}; } elsif ($action eq 'gtkset') { $_->destroy foreach $w->get_children; } foreach my $opt (qw(resize1 shrink1 resize2 shrink2)) { $opts->{$opt} = 1 if !defined $opts->{$opt}; } $w->pack1(delete $opts->{child1}, delete $opts->{resize1}, delete $opts->{shrink1}); $w->pack2(delete $opts->{child2}, delete $opts->{resize2}, delete $opts->{shrink2}); $w; } sub _gtk__VBox { &_gtk_any_Box } sub _gtk__HBox { &_gtk_any_Box } sub _gtk_any_Box { my ($w, $opts, $class, $action) = @_; if (!$w) { $w = "Gtk2::$class"->new(0,0); $w->set_homogeneous(delete $opts->{homogenous}) if exists $opts->{homogenous}; $w->set_spacing(delete $opts->{spacing}) if exists $opts->{spacing}; $w->set_border_width(delete $opts->{border_width}) if exists $opts->{border_width}; } elsif ($action eq 'gtkset') { $_->destroy foreach $w->get_children; } _gtknew_handle_children($w, $opts); $w; } sub _gtk__VButtonBox { &_gtk_any_ButtonBox } sub _gtk__HButtonBox { &_gtk_any_ButtonBox } sub _gtk_any_ButtonBox { my ($w, $opts, $class, $action) = @_; if (!$w) { $w = "Gtk2::$class"->new; $w->set_homogeneous(delete $opts->{homogenous}) if exists $opts->{homogenous}; $w->set_spacing(delete $opts->{spacing}) if exists $opts->{spacing}; $w->set_layout(delete $opts->{layout} || 'spread'); } elsif ($action eq 'gtkset') { $_->destroy foreach $w->get_children; } _gtknew_handle_children($w, $opts); $w; } sub _gtk__Notebook { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::Notebook->new; $w->set_property('show-tabs', delete $opts->{show_tabs}) if exists $opts->{show_tabs}; $w->set_property('show-border', delete $opts->{show_border}) if exists $opts->{show_border}; } if (exists $opts->{children}) { foreach (group_by2(@{delete $opts->{children}})) { my ($title, $page) = @$_; $w->append_page($page, $title); $page->show; $title->show; } } $w; } sub _gtk__Table { my ($w, $opts) = @_; if (!$w) { add2hash_($opts, { xpadding => 5, ypadding => 0, border_width => $::isInstall ? 3 : 10 }); $w = Gtk2::Table->new(0, 0, delete $opts->{homogeneous} || 0); $w->set_col_spacings(delete $opts->{col_spacings} || 0); $w->set_row_spacings(delete $opts->{row_spacings} || 0); $w->set_border_width(delete $opts->{border_width}); $w->{$_} = delete $opts->{$_} foreach 'xpadding', 'ypadding', 'mcc'; } each_index { my ($i, $l) = ($::i, $_); each_index { my $j = $::i; if ($_) { ref $_ or $_ = Gtk2::WrappedLabel->new($_); $j != $#$l && !$w->{mcc} ? $w->attach($_, $j, $j + 1, $i, $i + 1, 'fill', 'fill', $w->{xpadding}, $w->{ypadding}) : $w->attach($_, $j, $j + 1, $i, $i + 1, ['expand', 'fill'], ref($_) eq 'Gtk2::ScrolledWindow' || $_->get_data('must_grow') ? ['expand', 'fill'] : [], 0, 0); $_->show; } } @$l; } @{delete $opts->{children} || []}; $w; } sub _gtk_any_simple { my ($w, $_opts, $class) = @_; $w ||= "Gtk2::$class"->new; } sub _gtknew_handle_children { my ($w, $opts) = @_; my @child = exists $opts->{children_tight} ? map { [ 0, $_ ] } @{delete $opts->{children_tight}} : exists $opts->{children_loose} ? map { [ 1, $_ ] } @{delete $opts->{children_loose}} : exists $opts->{children} ? group_by2(@{delete $opts->{children}}) : exists $opts->{children_centered} ? ([ 1, gtknew('VBox') ], (map { [ 0, $_ ] } @{delete $opts->{children_centered}}), [ 1, gtknew('VBox') ]) : (); my $padding = delete $opts->{padding}; foreach (@child) { my ($fill, $child) = @$_; $fill eq '0' || $fill eq '1' || $fill eq 'fill' || $fill eq 'expand' or internal_error("odd {children} parameter must be 0 or 1 (got $fill)"); ref $child or $child = Gtk2::WrappedLabel->new($child); my $expand = $fill && $fill ne 'fill' ? 1 : 0; $w->pack_start($child, $expand, $fill, $padding || 0); $child->show; } } #- this magic function redirects method calls: #- * default is to redirect them to the {child} #- * if the {child} doesn't handle the method, we try with the {real_window} #- (eg : add_accel_group set_position set_default_size #- * a few methods are handled specially my %for_real_window = map { $_ => 1 } qw(show_all size_request); sub mygtk2::MagicWindow::AUTOLOAD { my ($w, @args) = @_; my ($meth) = $mygtk2::MagicWindow::AUTOLOAD =~ /mygtk2::MagicWindow::(.*)/; my ($s1, @s2) = $meth eq 'show' ? ('real_window', 'banner', 'child') : $meth eq 'destroy' || $meth eq 'hide' ? ($w->{pop_it} ? 'real_window' : ('child', 'banner')) : $meth eq 'get' && $args[0] eq 'window-position' || $for_real_window{$meth} || !$w->{child}->can($meth) ? 'real_window' : 'child'; #- warn "mygtk2::MagicWindow::$meth", first($w =~ /HASH(.*)/), " on $s1 @s2 (@args)\n"; $w->{$_} && $w->{$_}->$meth(@args) foreach @s2; $w->{$s1}->$meth(@args); } sub _create_Window { my ($opts) = @_; my $no_Window_Manager = exists $opts->{no_Window_Manager} ? delete $opts->{no_Window_Manager} : !$::isStandalone; add2hash($opts, { if_(!$::isInstall && !$::isWizard, border_width => 5), #- policy: during install, we need a special code to handle the weird centering, see below position_policy => $::isInstall ? 'none' : $no_Window_Manager ? 'center-always' : 'center-on-parent', if_($::isInstall, position => [ $::rootwidth - ($::o->{windowwidth} + $::real_windowwidth) / 2, $::logoheight + ($::o->{windowheight} - $::real_windowheight) / 2, ]), }); my $w = _gtk(undef, 'Window', 'gtknew', $opts); #- when the window is closed using the window manager "X" button (or alt-f4) $w->signal_connect(delete_event => sub { if ($::isWizard) { $w->destroy; die 'wizcancel'; } else { Gtk2->main_quit; } }); if ($no_Window_Manager) { _force_keyboard_focus($w); } if ($::isInstall) { require install::gtk; #- for perl_checker install::gtk::handle_unsafe_mouse($::o, $w); $w->signal_connect(key_press_event => \&install::gtk::special_shortcuts); #- force center at a weird position, this can't be handled by position_policy #- because center-on-parent is a window manager hint, and we don't have a WM my ($wi, $he); $w->signal_connect(size_allocate => sub { my (undef, $event) = @_; my @w_size = $event->values; return if $w_size[2] == $wi && $w_size[3] == $he; #BUG (undef, undef, $wi, $he) = @w_size; $w->move(max(0, $::rootwidth - ($::o->{windowwidth} + $wi) / 2), max(0, $::logoheight + ($::o->{windowheight} - $he) / 2)); }); #- without this, the focus is broken during install, though this is not needed during X test, why?? $w->show; } $w; } my $current_window; sub _force_keyboard_focus { my ($w) = @_; sub _XSetInputFocus { my ($w) = @_; if ($current_window == $w) { $w->window->XSetInputFocus; } 0; } #- force keyboard focus instead of mouse focus my $previous_current_window = $current_window; $current_window = $w; $w->signal_connect(expose_event => \&_XSetInputFocus); $w->signal_connect(destroy => sub { $current_window = $previous_current_window }); } sub _find_imgfile { my ($name) = @_; if ($name =~ m|/| && -f $name) { $name; } else { foreach my $path (_icon_paths()) { foreach ('', '.png', '.xpm') { my $file = "$path/$name$_"; -f $file and return $file; } } } } # _text_insert() can be used with any of choose one of theses styles: # - no tags: # _text_insert($textview, "My text.."); # - anonymous tags: # _text_insert($textview, [ [ 'first text', { 'foreground' => 'blue', 'background' => 'green', ... } ], # [ 'second text' ], # [ 'third', { 'font' => 'Serif 15', ... } ], # ... ]); # - named tags: # $textview->{tags} = { # 'blue_green' => { 'foreground' => 'blue', 'background' => 'green', ... }, # 'big_font' => { 'font' => 'Serif 35', ... }, # } # _text_insert($textview, [ [ 'first text', 'blue_green' ], # [ 'second', 'big_font' ], # ... ]); # - mixed anonymous and named tags: # $textview->{tags} = { # 'blue_green' => { 'foreground' => 'blue', 'background' => 'green', ... }, # 'big_font' => { 'font' => 'Serif 35', ... }, # } # _text_insert($textview, [ [ 'first text', 'blue_green' ], # [ 'second text' ], # [ 'third', 'big_font' ], # [ 'fourth', { 'font' => 'Serif 15', ... } ], # ... ]); sub _text_insert { my ($textview, $t, %opts) = @_; my $buffer = $textview->get_buffer; $buffer->{tags} ||= {}; $buffer->{gtk_tags} ||= {}; my $gtk_tags = $buffer->{gtk_tags}; my $tags = $buffer->{tags}; if (ref($t) eq 'ARRAY') { if (!$opts{append}) { $buffer->set_text(''); $textview->{anchors} = []; } foreach my $token (@$t) { my ($item, $tag) = @$token; my $iter1 = $buffer->get_end_iter; if ($item =~ /^Gtk2::Gdk::Pixbuf/) { $buffer->insert_pixbuf($iter1, $item); next; } if ($item =~ /^Gtk2::/) { my $anchor = $buffer->create_child_anchor($iter1); $textview->add_child_at_anchor($item, $anchor); $textview->{anchors} ||= []; push @{$textview->{anchors}}, $anchor; next; } if ($tag) { if (ref($tag)) { # use anonymous tags $buffer->insert_with_tags($iter1, $item, $buffer->create_tag(undef, %$tag)); } else { # fast text insertion: # since in some contexts (eg: localedrake, rpmdrake), we use quite a lot of identical tags, # it's much more efficient and less memory pressure to use named tags $gtk_tags->{$tag} ||= $buffer->create_tag($tag, %{$tags->{$token->[1]}}); $buffer->insert_with_tags($iter1, $item, $gtk_tags->{$tag}); } } else { $buffer->insert($iter1, $item); } } } else { if ($opts{append}) { $buffer->insert($buffer->get_end_iter, $t); } else { $textview->{anchors} = []; $buffer->set_text($t); } } $textview->{to_bottom}->() if $textview->{to_bottom}; #- the following line is needed to move the cursor to the beginning, so that if the #- textview has a scrollbar, it will not scroll to the bottom when focusing (#3633) $buffer->place_cursor($buffer->get_start_iter); $textview->set_wrap_mode($opts{wrap_mode} || 'word'); $textview->set_editable($opts{editable} || 0); $textview->set_cursor_visible($opts{visible} || 0); $textview; } sub _allow_scroll_TextView_to_bottom { my ($scrolledWindow, $textView) = @_; $textView->get_buffer->create_mark('end', $textView->get_buffer->get_end_iter, 0); sub { my ($o_force) = @_; my $adjustment = $scrolledWindow->get_vadjustment; if ($o_force || $adjustment->page_size + $adjustment->value == $adjustment->upper) { flush(); #- one must flush before scrolling to end, otherwise the text just added *may* not be taken into account correctly, and so it doesn't really scroll to end $textView->scroll_to_mark($textView->get_buffer->get_mark('end'), 0, 1, 0, 1); } }; } sub set_main_window_size { my ($window) = @_; my ($width, $height) = $::real_windowwidth ? ($::real_windowwidth, $::real_windowheight) : $::isWizard ? (540, 360) : (600, 400); $window->set_size_request($width, $height); } my @icon_paths; sub add_icon_path { push @icon_paths, @_ } sub _icon_paths() { (@icon_paths, (exists $ENV{SHARE_PATH} ? ($ENV{SHARE_PATH}, "$ENV{SHARE_PATH}/icons", "$ENV{SHARE_PATH}/libDrakX/pixmaps") : ()), "/usr/lib/libDrakX/icons", "pixmaps", 'data/icons', 'data/pixmaps', 'standalone/icons', '/usr/share/rpmdrake/icons'); } sub main { my ($window, $o_verif) = @_; my $destroyed; $window->signal_connect(destroy => sub { $destroyed = 1 }); $window->show; do { Gtk2->main } while (!$destroyed && $o_verif && !$o_verif->()); may_destroy($window); flush(); } sub sync { my ($window) = @_; $window->show; flush(); } sub flush() { Gtk2->main_iteration while Gtk2->events_pending; } sub may_destroy { my ($w) = @_; $w->destroy if $w; } sub root_window() { my $root if 0; $root ||= Gtk2::Gdk->get_default_root_window; } sub rgb2color { my ($r, $g, $b) = @_; my $color = Gtk2::Gdk::Color->new($r, $g, $b); root_window()->get_colormap->rgb_find_color($color); $color; } sub set_root_window_background { my ($r, $g, $b) = @_; my $root = root_window(); my $gc = Gtk2::Gdk::GC->new($root); my $color = rgb2color($r, $g, $b); $gc->set_rgb_fg_color($color); set_root_window_background_with_gc($gc); } sub set_root_window_background_with_gc { my ($gc) = @_; my $root = root_window(); my ($w, $h) = $root->get_size; $root->set_background($gc->get_values->{foreground}); $root->draw_rectangle($gc, 1, 0, 0, $w, $h); } sub pixmap_from_pixbuf { my ($widget, $pixbuf) = @_; my $window = $widget->window or internal_error("you can't use this function if the widget is not realised"); my ($width, $height) = ($pixbuf->get_width, $pixbuf->get_height); my $pixmap = Gtk2::Gdk::Pixmap->new($window, $width, $height, $window->get_depth); $pixbuf->render_to_drawable($pixmap, $widget->style->fg_gc('normal'), 0, 0, 0, 0, $width, $height, 'max', 0, 0); $pixmap; } 1; 25</a> <a id='n926' href='#n926'>926</a> <a id='n927' href='#n927'>927</a> <a id='n928' href='#n928'>928</a> <a id='n929' href='#n929'>929</a> <a id='n930' href='#n930'>930</a> <a id='n931' href='#n931'>931</a> <a id='n932' href='#n932'>932</a> <a id='n933' href='#n933'>933</a> <a id='n934' href='#n934'>934</a> <a id='n935' href='#n935'>935</a> <a id='n936' href='#n936'>936</a> <a id='n937' href='#n937'>937</a> <a id='n938' href='#n938'>938</a> <a id='n939' href='#n939'>939</a> <a id='n940' href='#n940'>940</a> <a id='n941' href='#n941'>941</a> <a id='n942' href='#n942'>942</a> <a id='n943' href='#n943'>943</a> <a id='n944' href='#n944'>944</a> <a id='n945' href='#n945'>945</a> <a id='n946' href='#n946'>946</a> <a id='n947' href='#n947'>947</a> <a id='n948' href='#n948'>948</a> <a id='n949' href='#n949'>949</a> <a id='n950' href='#n950'>950</a> <a id='n951' href='#n951'>951</a> <a id='n952' href='#n952'>952</a> <a id='n953' href='#n953'>953</a> <a id='n954' href='#n954'>954</a> <a id='n955' href='#n955'>955</a> <a id='n956' href='#n956'>956</a> <a id='n957' href='#n957'>957</a> <a id='n958' href='#n958'>958</a> <a id='n959' href='#n959'>959</a> <a id='n960' href='#n960'>960</a> <a id='n961' href='#n961'>961</a> <a id='n962' href='#n962'>962</a> <a id='n963' href='#n963'>963</a> <a id='n964' href='#n964'>964</a> <a id='n965' href='#n965'>965</a> <a id='n966' href='#n966'>966</a> <a id='n967' href='#n967'>967</a> <a id='n968' href='#n968'>968</a> <a id='n969' href='#n969'>969</a> <a id='n970' href='#n970'>970</a> <a id='n971' href='#n971'>971</a> <a id='n972' href='#n972'>972</a> <a id='n973' href='#n973'>973</a> <a id='n974' href='#n974'>974</a> <a id='n975' href='#n975'>975</a> <a id='n976' href='#n976'>976</a> <a id='n977' href='#n977'>977</a> <a id='n978' href='#n978'>978</a> <a id='n979' href='#n979'>979</a> <a id='n980' href='#n980'>980</a> <a id='n981' href='#n981'>981</a> <a id='n982' href='#n982'>982</a> <a id='n983' href='#n983'>983</a> <a id='n984' href='#n984'>984</a> <a id='n985' href='#n985'>985</a> <a id='n986' href='#n986'>986</a> <a id='n987' href='#n987'>987</a> <a id='n988' href='#n988'>988</a> <a id='n989' href='#n989'>989</a> <a id='n990' href='#n990'>990</a> <a id='n991' href='#n991'>991</a> <a id='n992' href='#n992'>992</a> <a id='n993' href='#n993'>993</a> <a id='n994' href='#n994'>994</a> <a id='n995' href='#n995'>995</a> <a id='n996' href='#n996'>996</a> <a id='n997' href='#n997'>997</a> <a id='n998' href='#n998'>998</a> <a id='n999' href='#n999'>999</a> <a id='n1000' href='#n1000'>1000</a> <a id='n1001' href='#n1001'>1001</a> <a id='n1002' href='#n1002'>1002</a> <a id='n1003' href='#n1003'>1003</a> <a id='n1004' href='#n1004'>1004</a> <a id='n1005' href='#n1005'>1005</a> <a id='n1006' href='#n1006'>1006</a> <a id='n1007' href='#n1007'>1007</a> <a id='n1008' href='#n1008'>1008</a> <a id='n1009' href='#n1009'>1009</a> <a id='n1010' href='#n1010'>1010</a> <a id='n1011' href='#n1011'>1011</a> <a id='n1012' href='#n1012'>1012</a> <a id='n1013' href='#n1013'>1013</a> <a id='n1014' href='#n1014'>1014</a> <a id='n1015' href='#n1015'>1015</a> <a id='n1016' href='#n1016'>1016</a> <a id='n1017' href='#n1017'>1017</a> <a id='n1018' href='#n1018'>1018</a> <a id='n1019' href='#n1019'>1019</a> <a id='n1020' href='#n1020'>1020</a> <a id='n1021' href='#n1021'>1021</a> <a id='n1022' href='#n1022'>1022</a> <a id='n1023' href='#n1023'>1023</a> <a id='n1024' href='#n1024'>1024</a> <a id='n1025' href='#n1025'>1025</a> <a id='n1026' href='#n1026'>1026</a> <a id='n1027' href='#n1027'>1027</a> <a id='n1028' href='#n1028'>1028</a> <a id='n1029' href='#n1029'>1029</a> <a id='n1030' href='#n1030'>1030</a> <a id='n1031' href='#n1031'>1031</a> <a id='n1032' href='#n1032'>1032</a> <a id='n1033' href='#n1033'>1033</a> <a id='n1034' href='#n1034'>1034</a> <a id='n1035' href='#n1035'>1035</a> <a id='n1036' href='#n1036'>1036</a> <a id='n1037' href='#n1037'>1037</a> <a id='n1038' href='#n1038'>1038</a> <a id='n1039' href='#n1039'>1039</a> <a id='n1040' href='#n1040'>1040</a> <a id='n1041' href='#n1041'>1041</a> <a id='n1042' href='#n1042'>1042</a> <a id='n1043' href='#n1043'>1043</a> <a id='n1044' href='#n1044'>1044</a> <a id='n1045' href='#n1045'>1045</a> <a id='n1046' href='#n1046'>1046</a> <a id='n1047' href='#n1047'>1047</a> <a id='n1048' href='#n1048'>1048</a> <a id='n1049' href='#n1049'>1049</a> <a id='n1050' href='#n1050'>1050</a> <a id='n1051' href='#n1051'>1051</a> <a id='n1052' href='#n1052'>1052</a> <a id='n1053' href='#n1053'>1053</a> <a id='n1054' href='#n1054'>1054</a> <a id='n1055' href='#n1055'>1055</a> <a id='n1056' href='#n1056'>1056</a> <a id='n1057' href='#n1057'>1057</a> <a id='n1058' href='#n1058'>1058</a> <a id='n1059' href='#n1059'>1059</a> <a id='n1060' href='#n1060'>1060</a> <a id='n1061' href='#n1061'>1061</a> <a id='n1062' href='#n1062'>1062</a> <a id='n1063' href='#n1063'>1063</a> <a id='n1064' href='#n1064'>1064</a> <a id='n1065' href='#n1065'>1065</a> <a id='n1066' href='#n1066'>1066</a> <a id='n1067' href='#n1067'>1067</a> <a id='n1068' href='#n1068'>1068</a> <a id='n1069' href='#n1069'>1069</a> <a id='n1070' href='#n1070'>1070</a> <a id='n1071' href='#n1071'>1071</a> <a id='n1072' href='#n1072'>1072</a> <a id='n1073' href='#n1073'>1073</a> <a id='n1074' href='#n1074'>1074</a> <a id='n1075' href='#n1075'>1075</a> <a id='n1076' href='#n1076'>1076</a> <a id='n1077' href='#n1077'>1077</a> <a id='n1078' href='#n1078'>1078</a> <a id='n1079' href='#n1079'>1079</a> <a id='n1080' href='#n1080'>1080</a> <a id='n1081' href='#n1081'>1081</a> <a id='n1082' href='#n1082'>1082</a> <a id='n1083' href='#n1083'>1083</a> <a id='n1084' href='#n1084'>1084</a> <a id='n1085' href='#n1085'>1085</a> <a id='n1086' href='#n1086'>1086</a> <a id='n1087' href='#n1087'>1087</a> <a id='n1088' href='#n1088'>1088</a> <a id='n1089' href='#n1089'>1089</a> <a id='n1090' href='#n1090'>1090</a> <a id='n1091' href='#n1091'>1091</a> <a id='n1092' href='#n1092'>1092</a> <a id='n1093' href='#n1093'>1093</a> <a id='n1094' href='#n1094'>1094</a> <a id='n1095' href='#n1095'>1095</a> <a id='n1096' href='#n1096'>1096</a> <a id='n1097' href='#n1097'>1097</a> <a id='n1098' href='#n1098'>1098</a> <a id='n1099' href='#n1099'>1099</a> <a id='n1100' href='#n1100'>1100</a> <a id='n1101' href='#n1101'>1101</a> <a id='n1102' href='#n1102'>1102</a> <a id='n1103' href='#n1103'>1103</a> <a id='n1104' href='#n1104'>1104</a> <a id='n1105' href='#n1105'>1105</a> <a id='n1106' href='#n1106'>1106</a> <a id='n1107' href='#n1107'>1107</a> <a id='n1108' href='#n1108'>1108</a> <a id='n1109' href='#n1109'>1109</a> <a id='n1110' href='#n1110'>1110</a> <a id='n1111' href='#n1111'>1111</a> <a id='n1112' href='#n1112'>1112</a> <a id='n1113' href='#n1113'>1113</a> <a id='n1114' href='#n1114'>1114</a> <a id='n1115' href='#n1115'>1115</a> <a id='n1116' href='#n1116'>1116</a> <a id='n1117' href='#n1117'>1117</a> <a id='n1118' href='#n1118'>1118</a> <a id='n1119' href='#n1119'>1119</a> <a id='n1120' href='#n1120'>1120</a> <a id='n1121' href='#n1121'>1121</a> <a id='n1122' href='#n1122'>1122</a> <a id='n1123' href='#n1123'>1123</a> <a id='n1124' href='#n1124'>1124</a> <a id='n1125' href='#n1125'>1125</a> <a id='n1126' href='#n1126'>1126</a> <a id='n1127' href='#n1127'>1127</a> <a id='n1128' href='#n1128'>1128</a> <a id='n1129' href='#n1129'>1129</a> <a id='n1130' href='#n1130'>1130</a> <a id='n1131' href='#n1131'>1131</a> <a id='n1132' href='#n1132'>1132</a> <a id='n1133' href='#n1133'>1133</a> <a id='n1134' href='#n1134'>1134</a> <a id='n1135' href='#n1135'>1135</a> <a id='n1136' href='#n1136'>1136</a> <a id='n1137' href='#n1137'>1137</a> <a id='n1138' href='#n1138'>1138</a> <a id='n1139' href='#n1139'>1139</a> <a id='n1140' href='#n1140'>1140</a> <a id='n1141' href='#n1141'>1141</a> <a id='n1142' href='#n1142'>1142</a> <a id='n1143' href='#n1143'>1143</a> <a id='n1144' href='#n1144'>1144</a> <a id='n1145' href='#n1145'>1145</a> <a id='n1146' href='#n1146'>1146</a> <a id='n1147' href='#n1147'>1147</a> <a id='n1148' href='#n1148'>1148</a> <a id='n1149' href='#n1149'>1149</a> <a id='n1150' href='#n1150'>1150</a> <a id='n1151' href='#n1151'>1151</a> <a id='n1152' href='#n1152'>1152</a> <a id='n1153' href='#n1153'>1153</a> <a id='n1154' href='#n1154'>1154</a> <a id='n1155' href='#n1155'>1155</a> <a id='n1156' href='#n1156'>1156</a> <a id='n1157' href='#n1157'>1157</a> <a id='n1158' href='#n1158'>1158</a> <a id='n1159' href='#n1159'>1159</a> <a id='n1160' href='#n1160'>1160</a> <a id='n1161' href='#n1161'>1161</a> <a id='n1162' href='#n1162'>1162</a> <a id='n1163' href='#n1163'>1163</a> <a id='n1164' href='#n1164'>1164</a> <a id='n1165' href='#n1165'>1165</a> <a id='n1166' href='#n1166'>1166</a> <a id='n1167' href='#n1167'>1167</a> <a id='n1168' href='#n1168'>1168</a> <a id='n1169' href='#n1169'>1169</a> <a id='n1170' href='#n1170'>1170</a> <a id='n1171' href='#n1171'>1171</a> <a id='n1172' href='#n1172'>1172</a> <a id='n1173' href='#n1173'>1173</a> <a id='n1174' href='#n1174'>1174</a> <a id='n1175' href='#n1175'>1175</a> <a id='n1176' href='#n1176'>1176</a> <a id='n1177' href='#n1177'>1177</a> <a id='n1178' href='#n1178'>1178</a> <a id='n1179' href='#n1179'>1179</a> <a id='n1180' href='#n1180'>1180</a> <a id='n1181' href='#n1181'>1181</a> <a id='n1182' href='#n1182'>1182</a> <a id='n1183' href='#n1183'>1183</a> <a id='n1184' href='#n1184'>1184</a> <a id='n1185' href='#n1185'>1185</a> <a id='n1186' href='#n1186'>1186</a> <a id='n1187' href='#n1187'>1187</a> <a id='n1188' href='#n1188'>1188</a> <a id='n1189' href='#n1189'>1189</a> <a id='n1190' href='#n1190'>1190</a> <a id='n1191' href='#n1191'>1191</a> <a id='n1192' href='#n1192'>1192</a> <a id='n1193' href='#n1193'>1193</a> <a id='n1194' href='#n1194'>1194</a> <a id='n1195' href='#n1195'>1195</a> <a id='n1196' href='#n1196'>1196</a> <a id='n1197' href='#n1197'>1197</a> <a id='n1198' href='#n1198'>1198</a> <a id='n1199' href='#n1199'>1199</a> <a id='n1200' href='#n1200'>1200</a> <a id='n1201' href='#n1201'>1201</a> <a id='n1202' href='#n1202'>1202</a> <a id='n1203' href='#n1203'>1203</a> <a id='n1204' href='#n1204'>1204</a> <a id='n1205' href='#n1205'>1205</a> <a id='n1206' href='#n1206'>1206</a> <a id='n1207' href='#n1207'>1207</a> <a id='n1208' href='#n1208'>1208</a> <a id='n1209' href='#n1209'>1209</a> <a id='n1210' href='#n1210'>1210</a> <a id='n1211' href='#n1211'>1211</a> <a id='n1212' href='#n1212'>1212</a> <a id='n1213' href='#n1213'>1213</a> <a id='n1214' href='#n1214'>1214</a> <a id='n1215' href='#n1215'>1215</a> <a id='n1216' href='#n1216'>1216</a> <a id='n1217' href='#n1217'>1217</a> <a id='n1218' href='#n1218'>1218</a> <a id='n1219' href='#n1219'>1219</a> <a id='n1220' href='#n1220'>1220</a> <a id='n1221' href='#n1221'>1221</a> <a id='n1222' href='#n1222'>1222</a> <a id='n1223' href='#n1223'>1223</a> <a id='n1224' href='#n1224'>1224</a> <a id='n1225' href='#n1225'>1225</a> <a id='n1226' href='#n1226'>1226</a> <a id='n1227' href='#n1227'>1227</a> <a id='n1228' href='#n1228'>1228</a> <a id='n1229' href='#n1229'>1229</a> <a id='n1230' href='#n1230'>1230</a> <a id='n1231' href='#n1231'>1231</a> <a id='n1232' href='#n1232'>1232</a> <a id='n1233' href='#n1233'>1233</a> <a id='n1234' href='#n1234'>1234</a> <a id='n1235' href='#n1235'>1235</a> <a id='n1236' href='#n1236'>1236</a> <a id='n1237' href='#n1237'>1237</a> <a id='n1238' href='#n1238'>1238</a> <a id='n1239' href='#n1239'>1239</a> <a id='n1240' href='#n1240'>1240</a> <a id='n1241' href='#n1241'>1241</a> <a id='n1242' href='#n1242'>1242</a> <a id='n1243' href='#n1243'>1243</a> <a id='n1244' href='#n1244'>1244</a> <a id='n1245' href='#n1245'>1245</a> <a id='n1246' href='#n1246'>1246</a> <a id='n1247' href='#n1247'>1247</a> <a id='n1248' href='#n1248'>1248</a> <a id='n1249' href='#n1249'>1249</a> <a id='n1250' href='#n1250'>1250</a> <a id='n1251' href='#n1251'>1251</a> <a id='n1252' href='#n1252'>1252</a> <a id='n1253' href='#n1253'>1253</a> <a id='n1254' href='#n1254'>1254</a> <a id='n1255' href='#n1255'>1255</a> <a id='n1256' href='#n1256'>1256</a> <a id='n1257' href='#n1257'>1257</a> <a id='n1258' href='#n1258'>1258</a> <a id='n1259' href='#n1259'>1259</a> <a id='n1260' href='#n1260'>1260</a> <a id='n1261' href='#n1261'>1261</a> <a id='n1262' href='#n1262'>1262</a> <a id='n1263' href='#n1263'>1263</a> <a id='n1264' href='#n1264'>1264</a> <a id='n1265' href='#n1265'>1265</a> <a id='n1266' href='#n1266'>1266</a> <a id='n1267' href='#n1267'>1267</a> <a id='n1268' href='#n1268'>1268</a> <a id='n1269' href='#n1269'>1269</a> <a id='n1270' href='#n1270'>1270</a> <a id='n1271' href='#n1271'>1271</a> <a id='n1272' href='#n1272'>1272</a> <a id='n1273' href='#n1273'>1273</a> <a id='n1274' href='#n1274'>1274</a> <a id='n1275' href='#n1275'>1275</a> <a id='n1276' href='#n1276'>1276</a> <a id='n1277' href='#n1277'>1277</a> <a id='n1278' href='#n1278'>1278</a> <a id='n1279' href='#n1279'>1279</a> <a id='n1280' href='#n1280'>1280</a> <a id='n1281' href='#n1281'>1281</a> <a id='n1282' href='#n1282'>1282</a> <a id='n1283' href='#n1283'>1283</a> <a id='n1284' href='#n1284'>1284</a> <a id='n1285' href='#n1285'>1285</a> <a id='n1286' href='#n1286'>1286</a> <a id='n1287' href='#n1287'>1287</a> <a id='n1288' href='#n1288'>1288</a> <a id='n1289' href='#n1289'>1289</a> <a id='n1290' href='#n1290'>1290</a> <a id='n1291' href='#n1291'>1291</a> <a id='n1292' href='#n1292'>1292</a> <a id='n1293' href='#n1293'>1293</a> <a id='n1294' href='#n1294'>1294</a> <a id='n1295' href='#n1295'>1295</a> <a id='n1296' href='#n1296'>1296</a> <a id='n1297' href='#n1297'>1297</a> <a id='n1298' href='#n1298'>1298</a> <a id='n1299' href='#n1299'>1299</a> <a id='n1300' href='#n1300'>1300</a> <a id='n1301' href='#n1301'>1301</a> <a id='n1302' href='#n1302'>1302</a> <a id='n1303' href='#n1303'>1303</a> <a id='n1304' href='#n1304'>1304</a> <a id='n1305' href='#n1305'>1305</a> <a id='n1306' href='#n1306'>1306</a> <a id='n1307' href='#n1307'>1307</a> <a id='n1308' href='#n1308'>1308</a> <a id='n1309' href='#n1309'>1309</a> <a id='n1310' href='#n1310'>1310</a> <a id='n1311' href='#n1311'>1311</a> <a id='n1312' href='#n1312'>1312</a> <a id='n1313' href='#n1313'>1313</a> <a id='n1314' href='#n1314'>1314</a> <a id='n1315' href='#n1315'>1315</a> <a id='n1316' href='#n1316'>1316</a> <a id='n1317' href='#n1317'>1317</a> <a id='n1318' href='#n1318'>1318</a> <a id='n1319' href='#n1319'>1319</a> <a id='n1320' href='#n1320'>1320</a> <a id='n1321' href='#n1321'>1321</a> <a id='n1322' href='#n1322'>1322</a> <a id='n1323' href='#n1323'>1323</a> <a id='n1324' href='#n1324'>1324</a> <a id='n1325' href='#n1325'>1325</a> <a id='n1326' href='#n1326'>1326</a> <a id='n1327' href='#n1327'>1327</a> <a id='n1328' href='#n1328'>1328</a> <a id='n1329' href='#n1329'>1329</a> <a id='n1330' href='#n1330'>1330</a> <a id='n1331' href='#n1331'>1331</a> <a id='n1332' href='#n1332'>1332</a> <a id='n1333' href='#n1333'>1333</a> <a id='n1334' href='#n1334'>1334</a> <a id='n1335' href='#n1335'>1335</a> <a id='n1336' href='#n1336'>1336</a> <a id='n1337' href='#n1337'>1337</a> <a id='n1338' href='#n1338'>1338</a> <a id='n1339' href='#n1339'>1339</a> <a id='n1340' href='#n1340'>1340</a> <a id='n1341' href='#n1341'>1341</a> <a id='n1342' href='#n1342'>1342</a> <a id='n1343' href='#n1343'>1343</a> <a id='n1344' href='#n1344'>1344</a> <a id='n1345' href='#n1345'>1345</a> <a id='n1346' href='#n1346'>1346</a> <a id='n1347' href='#n1347'>1347</a> <a id='n1348' href='#n1348'>1348</a> <a id='n1349' href='#n1349'>1349</a> <a id='n1350' href='#n1350'>1350</a> <a id='n1351' href='#n1351'>1351</a> <a id='n1352' href='#n1352'>1352</a> <a id='n1353' href='#n1353'>1353</a> <a id='n1354' href='#n1354'>1354</a> <a id='n1355' href='#n1355'>1355</a> <a id='n1356' href='#n1356'>1356</a> <a id='n1357' href='#n1357'>1357</a> <a id='n1358' href='#n1358'>1358</a> <a id='n1359' href='#n1359'>1359</a> <a id='n1360' href='#n1360'>1360</a> <a id='n1361' href='#n1361'>1361</a> <a id='n1362' href='#n1362'>1362</a> <a id='n1363' href='#n1363'>1363</a> <a id='n1364' href='#n1364'>1364</a> <a id='n1365' href='#n1365'>1365</a> <a id='n1366' href='#n1366'>1366</a> <a id='n1367' href='#n1367'>1367</a> <a id='n1368' href='#n1368'>1368</a> <a id='n1369' href='#n1369'>1369</a> <a id='n1370' href='#n1370'>1370</a> <a id='n1371' href='#n1371'>1371</a> <a id='n1372' href='#n1372'>1372</a> <a id='n1373' href='#n1373'>1373</a> <a id='n1374' href='#n1374'>1374</a> <a id='n1375' href='#n1375'>1375</a> <a id='n1376' href='#n1376'>1376</a> <a id='n1377' href='#n1377'>1377</a> <a id='n1378' href='#n1378'>1378</a> <a id='n1379' href='#n1379'>1379</a> <a id='n1380' href='#n1380'>1380</a> <a id='n1381' href='#n1381'>1381</a> <a id='n1382' href='#n1382'>1382</a> <a id='n1383' href='#n1383'>1383</a> <a id='n1384' href='#n1384'>1384</a> <a id='n1385' href='#n1385'>1385</a> <a id='n1386' href='#n1386'>1386</a> <a id='n1387' href='#n1387'>1387</a> <a id='n1388' href='#n1388'>1388</a> <a id='n1389' href='#n1389'>1389</a> <a id='n1390' href='#n1390'>1390</a> <a id='n1391' href='#n1391'>1391</a> <a id='n1392' href='#n1392'>1392</a> <a id='n1393' href='#n1393'>1393</a> <a id='n1394' href='#n1394'>1394</a> <a id='n1395' href='#n1395'>1395</a> <a id='n1396' href='#n1396'>1396</a> <a id='n1397' href='#n1397'>1397</a> <a id='n1398' href='#n1398'>1398</a> <a id='n1399' href='#n1399'>1399</a> <a id='n1400' href='#n1400'>1400</a> <a id='n1401' href='#n1401'>1401</a> <a id='n1402' href='#n1402'>1402</a> <a id='n1403' href='#n1403'>1403</a> <a id='n1404' href='#n1404'>1404</a> <a id='n1405' href='#n1405'>1405</a> <a id='n1406' href='#n1406'>1406</a> <a id='n1407' href='#n1407'>1407</a> <a id='n1408' href='#n1408'>1408</a> <a id='n1409' href='#n1409'>1409</a> <a id='n1410' href='#n1410'>1410</a> <a id='n1411' href='#n1411'>1411</a> <a id='n1412' href='#n1412'>1412</a> <a id='n1413' href='#n1413'>1413</a> <a id='n1414' href='#n1414'>1414</a> <a id='n1415' href='#n1415'>1415</a> <a id='n1416' href='#n1416'>1416</a> <a id='n1417' href='#n1417'>1417</a> <a id='n1418' href='#n1418'>1418</a> <a id='n1419' href='#n1419'>1419</a> <a id='n1420' href='#n1420'>1420</a> <a id='n1421' href='#n1421'>1421</a> <a id='n1422' href='#n1422'>1422</a> <a id='n1423' href='#n1423'>1423</a> <a id='n1424' href='#n1424'>1424</a> <a id='n1425' href='#n1425'>1425</a> <a id='n1426' href='#n1426'>1426</a> <a id='n1427' href='#n1427'>1427</a> <a id='n1428' href='#n1428'>1428</a> <a id='n1429' href='#n1429'>1429</a> <a id='n1430' href='#n1430'>1430</a> <a id='n1431' href='#n1431'>1431</a> <a id='n1432' href='#n1432'>1432</a> <a id='n1433' href='#n1433'>1433</a> <a id='n1434' href='#n1434'>1434</a> <a id='n1435' href='#n1435'>1435</a> <a id='n1436' href='#n1436'>1436</a> <a id='n1437' href='#n1437'>1437</a> <a id='n1438' href='#n1438'>1438</a> <a id='n1439' href='#n1439'>1439</a> <a id='n1440' href='#n1440'>1440</a> <a id='n1441' href='#n1441'>1441</a> <a id='n1442' href='#n1442'>1442</a> <a id='n1443' href='#n1443'>1443</a> <a id='n1444' href='#n1444'>1444</a> <a id='n1445' href='#n1445'>1445</a> <a id='n1446' href='#n1446'>1446</a> <a id='n1447' href='#n1447'>1447</a> <a id='n1448' href='#n1448'>1448</a> <a id='n1449' href='#n1449'>1449</a> <a id='n1450' href='#n1450'>1450</a> <a id='n1451' href='#n1451'>1451</a> <a id='n1452' href='#n1452'>1452</a> <a id='n1453' href='#n1453'>1453</a> <a id='n1454' href='#n1454'>1454</a> <a id='n1455' href='#n1455'>1455</a> <a id='n1456' href='#n1456'>1456</a> <a id='n1457' href='#n1457'>1457</a> <a id='n1458' href='#n1458'>1458</a> <a id='n1459' href='#n1459'>1459</a> <a id='n1460' href='#n1460'>1460</a> <a id='n1461' href='#n1461'>1461</a> <a id='n1462' href='#n1462'>1462</a> <a id='n1463' href='#n1463'>1463</a> <a id='n1464' href='#n1464'>1464</a> <a id='n1465' href='#n1465'>1465</a> <a id='n1466' href='#n1466'>1466</a> <a id='n1467' href='#n1467'>1467</a> <a id='n1468' href='#n1468'>1468</a> <a id='n1469' href='#n1469'>1469</a> <a id='n1470' href='#n1470'>1470</a> <a id='n1471' href='#n1471'>1471</a> <a id='n1472' href='#n1472'>1472</a> <a id='n1473' href='#n1473'>1473</a> <a id='n1474' href='#n1474'>1474</a> <a id='n1475' href='#n1475'>1475</a> <a id='n1476' href='#n1476'>1476</a> <a id='n1477' href='#n1477'>1477</a> <a id='n1478' href='#n1478'>1478</a> <a id='n1479' href='#n1479'>1479</a> <a id='n1480' href='#n1480'>1480</a> <a id='n1481' href='#n1481'>1481</a> <a id='n1482' href='#n1482'>1482</a> <a id='n1483' href='#n1483'>1483</a> <a id='n1484' href='#n1484'>1484</a> <a id='n1485' href='#n1485'>1485</a> <a id='n1486' href='#n1486'>1486</a> <a id='n1487' href='#n1487'>1487</a> <a id='n1488' href='#n1488'>1488</a> <a id='n1489' href='#n1489'>1489</a> <a id='n1490' href='#n1490'>1490</a> <a id='n1491' href='#n1491'>1491</a> <a id='n1492' href='#n1492'>1492</a> <a id='n1493' href='#n1493'>1493</a> <a id='n1494' href='#n1494'>1494</a> <a id='n1495' href='#n1495'>1495</a> <a id='n1496' href='#n1496'>1496</a> <a id='n1497' href='#n1497'>1497</a> <a id='n1498' href='#n1498'>1498</a> <a id='n1499' href='#n1499'>1499</a> <a id='n1500' href='#n1500'>1500</a> <a id='n1501' href='#n1501'>1501</a> <a id='n1502' href='#n1502'>1502</a> <a id='n1503' href='#n1503'>1503</a> <a id='n1504' href='#n1504'>1504</a> <a id='n1505' href='#n1505'>1505</a> <a id='n1506' href='#n1506'>1506</a> <a id='n1507' href='#n1507'>1507</a> <a id='n1508' href='#n1508'>1508</a> <a id='n1509' href='#n1509'>1509</a> <a id='n1510' href='#n1510'>1510</a> <a id='n1511' href='#n1511'>1511</a> </pre></td> <td class='lines'><pre><code>