package mygtk2; use diagnostics; use strict; use feature 'state'; 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; sub 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'), if_($::isInstall, 'draksnapshot'), 'drakx-net', 'drakx-kbd-mouse-x11', # shared translation @::textdomains; Gtk2->croak_execeptions; } init() unless ($::no_ugtk_init); Gtk2->croak_execeptions if $::isInstall; 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 (my $sensitive_ref = delete $opts->{sensitive_ref}) { my $set = sub { $w->set_sensitive($$sensitive_ref) }; gtkval_register($w, $sensitive_ref, $set); $set->(); } if (%$opts && !$opts->{allow_unknown_options}) { internal_error("$action $class: unknown option(s) " . join(', ', keys %$opts)); } $w; } sub _gtk__Install_Button { my ($w, $opts, $class) = @_; $opts->{widget_name} = 'Banner'; $opts->{child} = gtknew('HBox', spacing => 5, children_tight => [ # FIXME: not RTL compliant (lang::text_direction_rtl() ? ...) gtknew('Image', file => 'advanced_expander'), gtknew('Label', text => delete $opts->{text}), ], ); $opts->{relief} = 'none'; _gtk__Button($w, $opts, 'Button'); } 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}); } elsif (exists $opts->{stock}) { $w->set_label(delete $opts->{stock}); $w->set_use_stock(1); } 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} ||= [ $left_padding, 0 ]; _gtk__WrappedLabel($w, $opts); } sub _gtk__Label_Right { my ($w, $opts) = @_; $opts->{alignment} ||= [ 1, 0.5 ]; _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 _gtk__Alignment { my ($w, $opts) = @_; if (!$w) { $w = Gtk2::Alignment->new(0, 0, 0, 0); } $w; } sub title1_to_markup { my ($label) = @_; $::isInstall ? '' . $label . '' : '' . $label . ''; } sub _gtk__Install_Title { my ($w, $opts) = @_; local $opts->{widget_name} = 'Banner'; gtknew('HBox', widget_name => 'Banner', children => [ 0, gtknew('Label', padding => [ 6, 0 ]), 1, gtknew('VBox', widget_name => 'Banner', children_tight => [ _gtk__Title2($w, $opts), if_($::isInstall, Gtk2::HSeparator->new), ]), 0, gtknew('Label', padding => [ 6, 0 ]), ]); } sub _gtk__Title1 { my ($w, $opts) = @_; $opts ||= {}; $opts->{text_markup} = title1_to_markup(delete($opts->{label})) if $opts->{label}; _gtk__WrappedLabel($w, $opts); } sub _gtk__Title2 { my ($w, $opts) = @_; $opts ||= {}; $opts->{alignment} = [ 0, 0 ]; _gtk__Title1($w, $opts); } sub _gtk__Sexy_IconEntry { my ($w, $opts) = @_; require Gtk2::Sexy; if (!$w) { $w = Gtk2::Sexy::IconEntry->new; $w->set_editable(delete $opts->{editable}) if exists $opts->{editable}; } $w->add_clear_button if delete $opts->{clear_button}; if (my $icon = delete $opts->{primary_icon}) { $w->set_icon('primary', $icon); $w->set_icon_highlight('primary', $icon); } if (my $icon = delete $opts->{secondary_icon}) { $w->set_icon('secondary',i $icon); $w->set_icon_highlight('secondary', $icon); } $w->signal_connect('icon-released' => delete $opts->{'icon-released'}) if exists $opts->{'icon-released'}; $w->signal_connect('icon-pressed' => delete $opts->{'icon-pressed'}) if exists $opts->{'icon-pressed'}; _gtk__Entry($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->get_left_margin() <= 6; $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::SimpleList|Gtk2::Html2|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__Fixed { my ($w, $opts, $_class, $action) = @_; if (!$w) { $w = Gtk2::Fixed->new; $w->set_has_window(delete $opts->{has_window}) if exists $opts->{has_window}; $w->put(delete $opts->{child}, delete $opts->{x}, delete $opts->{y}) if exists $opts->{child}; if ($opts->{pixbuf_file}) { my $pixbuf = gtknew('Pixbuf', file => delete $opts->{pixbuf_file}) if $opts->{pixbuf_file}; $w->signal_connect( realize => sub { ugtk2::set_back_pixbuf($w, $pixbuf); }); } } $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_type_hint('dialog'); # for matchbox window manager $w->set_modal(delete $opts->{modal}) if exists $opts->{modal}; $opts->{transient_for} ||= $::main_window if $::main_window; $w->set_modal(1) if exists $opts->{transient_for}; $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; } my $previous_popped_and_reuse_window; sub destroy_previous_popped_and_reuse_window() { $previous_popped_and_reuse_window or return; $previous_popped_and_reuse_window->destroy; $previous_popped_and_reuse_window = undef; } 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 # FIXME!!! any { !$_->isa('Gtk2::DrawingArea') && $_->visible } $::WizardTable->get_children; }; my $pop_and_reuse = delete $opts->{pop_and_reuse} && $pop_it; 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_and_reuse) { destroy_previous_popped_and_reuse_window(); } if ($previous_popped_and_reuse_window && $pop_and_reuse) { $w = $previous_popped_and_reuse_window; $w->remove($w->child); gtkadd($w, child => $sub_child); %$opts = (); } elsif ($pop_it) { $opts->{child} = $sub_child; $w = _create_Window($opts, pop_and_reuse => $pop_and_reuse); $previous_popped_and_reuse_window = $w if $pop_and_reuse; } 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 => $::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, pop_and_reuse => $pop_and_reuse, 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_program_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}; $w->set_position(delete $opts->{position}) if exists $opts->{position}; } 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_border_width(delete $opts->{border_width}) if exists $opts->{border_width}; $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 ? ($opts->{modal} ? 'center-always' : 'none') : $no_Window_Manager ? 'center-always' : 'center-on-parent', if_($::isInstall, position => [ $::stepswidth + ($::o->{windowwidth} - $::real_windowwidth) / 2, ($::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 { if (Gtk2->main_level) { Gtk2->main_quit; } else { # block window deletion if not in main loop (eg: while starting the GUI) return 1; } } }); 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-* really are window manager hints for centering, whereas we want #- to center the main window in the right part of the screen my ($wi, $he); $w->signal_connect(size_allocate => sub { my (undef, $event) = @_; my @w_size = $event->values; # ignore bogus sizing events: return if $w_size[2] < 5; 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, ($::o->{windowheight} - $he) / 2)); }); } $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', '.jpg') { 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 asteriskize { my ($label) = @_; "\x{2022} " . $label; } sub get_main_window_size() { my ($width, $height) = $::real_windowwidth ? ($::real_windowwidth, $::real_windowheight) : $::isWizard ? (540, 360) : (600, 400); } our $left_padding = 20; # in order to workaround infamous 6 years old gnome bug #101968: sub get_label_width() { first(mygtk2::get_main_window_size()) - 50 - $left_padding; } sub set_main_window_size { my ($window) = @_; my ($width, $height) = get_main_window_size(); $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) = @_; return if !$w; @::main_windows = difference2(\@::main_windows, [ $w->{real_window} ]); if ($::main_window eq $w->{real_window}) { undef $::main_window; $::main_window = $::main_windows[-1]; } $w->destroy; } sub root_window() { state $root; $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; id='n1121' href='#n1121'>1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127
#
# Latest versions of po files are at http://www.mandrakelinux.com/l10n/ru.php3
#
# Russian translation of rpmdrake messages
# Copyright (C) 2003 Free Software Foundation, Inc.
# Aleksey Smirnov <smi@logic.ru>, 2000
# Vladimir Choundalov <choundalovvv@point.pwp.ru>, 2001
# Pavel Maryanov <acid_jack@ukr.net>, 2003
#
msgid ""
msgstr ""
"Project-Id-Version: rpmdrake\n"
"POT-Creation-Date: 2003-07-30 11:50+0200\n"
"PO-Revision-Date: 2003-07-23 11:13+0200\n"
"Last-Translator: Pavel Maryanov <acid_jack@ukr.net>\n"
"Language-Team: Russian <cooker-i18n@linux-mandrake.com >\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=KOI8-R\n"
"Content-Transfer-Encoding: 8bit\n"

#: ../rpmdrake:1
#, c-format
msgid "Enlightenment"
msgstr "Enlightenment"

#: ../rpmdrake:1
#, c-format
msgid "Remote access"
msgstr "Удаленный доступ"

#: ../edit-urpm-sources.pl:1 ../rpmdrake.pm:1
#, c-format
msgid "Please wait, updating media..."
msgstr "Пожалуйста, подождите, обновляется носитель..."

#: ../rpmdrake:1
#, c-format
msgid "FVWM based"
msgstr "На основе FVWM"

#: ../rpmdrake.pm:1
#, c-format
msgid "Canada"
msgstr "Канада"

#: ../rpmdrake:1
#, c-format
msgid "Python"
msgstr "Python"

#: ../rpmdrake:1
#, c-format
msgid "Upgradable"
msgstr "Можно обновить"

#: ../rpmdrake:1
#, c-format
msgid "everything was installed correctly"
msgstr "все было установлено правильно"

#: ../rpmdrake:1
#, c-format
msgid "Verifying packages signatures..."
msgstr "Проверяются подписи пакетов..."

#: ../rpmdrake:1
#, c-format
msgid "File transfer"
msgstr "Передача файла"

#: ../rpmdrake:1
#, c-format
msgid "KDE and Qt"
msgstr "KDE и Qt"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "You need to fill up at least the two first entries."
msgstr "Вам необходимо заполнить по крайней мере два первых пункта."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Type of medium:"
msgstr "Тип источника:"

#: ../rpmdrake.pm:1
#, c-format
msgid "Copying file for medium `%s'..."
msgstr "Копируется файл для источника `%s'..."

#: ../rpmdrake.pm:1
#, c-format
msgid "France"
msgstr "Франция"

#: ../rpmdrake:1
#, c-format
msgid ""
"I need to contact the mirror to get latest update packages.\n"
"Please check that your network is currently running.\n"
"\n"
"Is it ok to continue?"
msgstr ""
"Мне необходимо связаться с зеркалом, чтобы получить самые\n"
"последние пакеты обновлений. Пожалуйста, убедитесь,\n"
"что ваша сеть в данный момент работает.\n"
"Все в порядке? Можно продолжать?"

#: ../rpmdrake:1
#, c-format
msgid "Search results"
msgstr "Результаты поиска"

#: ../rpmdrake:1
#, c-format
msgid "Graphical desktop"
msgstr "Графический рабочий стол"

#: ../rpmdrake.pm:1
#, c-format
msgid "Yes"
msgstr "Да"

#: ../rpmdrake:1
#, c-format
msgid ""
"The installation is finished; %s.\n"
"\n"
"Some configuration files were created as `.rpmnew' or `.rpmsave',\n"
"you may now inspect some in order to take actions:"
msgstr ""
"Установка завершена; %s.\n"
"\n"
"Некоторые файлы настройки были созданы как `.rpmnew' или `.rpmsave',\n"
"теперь вы можете просмотреть их чтобы принять меры:"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Edit a parallel group"
msgstr "Редактировать параллельную группу"

#: ../rpmdrake:1
#, c-format
msgid "How to choose manually your mirror"
msgstr "Как вручную выбрать свое зеркало"

#: ../rpmdrake:1
#, c-format
msgid "Publishing"
msgstr "Издательство"

#: ../rpmdrake:1
#, c-format
msgid "Package installation..."
msgstr "Устанавливается пакет..."

#: ../rpmdrake:1
#, c-format
msgid "GNOME and GTK+"
msgstr "GNOME и GTK+"

#: ../rpmdrake.pm:1
#, c-format
msgid "Select the media you wish to update:"
msgstr "Выберите источник, который вы хотите обновить:"

#: ../rpmdrake:1
#, c-format
msgid "Software Packages Removal"
msgstr "Удаление пакетов программ"

#: ../rpmdrake:1
#, c-format
msgid "Shells"
msgstr "Командные процессоры"

#: ../rpmdrake:1
#, c-format
msgid "Chemistry"
msgstr "Химия"

#: ../rpmdrake:1
#, c-format
msgid "True type"
msgstr "True type"

#: ../rpmdrake:1
#, c-format
msgid "Base"
msgstr "Стандартные"

#: ../rpmdrake:1
#, c-format
msgid "Graphics"
msgstr "Графика"

#: ../rpmdrake.pm:1
#, c-format
msgid "Italy"
msgstr "Италия"

#: ../rpmdrake:1
#, c-format
msgid ""
"You are launching this program as a normal user.\n"
"You will not be able to perform modifications on the system,\n"
"but you may still browse the existing database."
msgstr ""
"Вы запускаете эту программу как обычный пользователь.\n"
"Вы не сможете применить изменения в системе, но\n"
"вы все-таки сможете просмотреть существующую\n"
"базу данных."

#: ../rpmdrake:1
#, c-format
msgid "One of the following packages is needed:"
msgstr "Нужен один из следующих пакетов:"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "URL:"
msgstr "URL:"

#: ../rpmdrake:1
#, c-format
msgid "Information on packages"
msgstr "Информация о пакетах"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Proxy..."
msgstr "Прокси..."

#: ../rpmdrake.pm:1
#, c-format
msgid "Russia"
msgstr "Россия"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid ""
"If you need a proxy, enter the hostname and an optional port (syntax: "
"<proxyhost[:port]>):"
msgstr ""
"Если вам нужен прокси, введите имя хоста и при необходимости порт "
"(синтаксис: <хост_прокси[:порт]>):"

#: ../rpmdrake:1
#, c-format
msgid ""
"Because of their dependencies, the following package(s) must be\n"
"unselected now:\n"
"\n"
msgstr ""
"Из-за своих зависимостей следующие пакеты не должны\n"
"быть сейчас выбраны:\n"
"\n"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Configure parallel urpmi (distributed execution of urpmi)"
msgstr "Настроить параллельный urpmi (распределенное выполнение urpmi)"

#: ../rpmdrake:1
#, c-format
msgid "Sound"
msgstr "Звук"

#: ../rpmdrake:1
#, c-format
msgid "Changelog:\n"
msgstr "Changelog:\n"

#: ../rpmdrake.pm:1
#, c-format
msgid ""
"I need to contact MandrakeSoft website to get the mirrors list.\n"
"Please check that your network is currently running.\n"
"\n"
"Is it ok to continue?"
msgstr ""
"Мне необходимо связаться с веб-сайтом MandrakeSoft, чтобы получить\n"
" список зеркал. Пожалуйста, убедитесь, что ваша сеть в настоящий\n"
"момент работает.\n"
"Все в порядке? Можно продолжать?"

#: ../rpmdrake:1
#, c-format
msgid "Please wait, searching..."
msgstr "Пожалуйста, подождите, выполняется поиск..."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Command"
msgstr "Команда"

#: ../rpmdrake:1 ../edit-urpm-sources.pl:1
#, c-format
msgid ""
"%s\n"
"\n"
"Is it ok to continue?"
msgstr ""
"%s\n"
"\n"
"Все в порядке? Можно продолжать?"

#: ../rpmdrake:1
#, c-format
msgid "Literature"
msgstr "Литература"

#: ../rpmdrake:1
#, c-format
msgid "Initializing..."
msgstr "Инициализация..."

#: ../rpmdrake:1
#, c-format
msgid ""
"The list of updates is void. This means that either there is\n"
"no available update for the packages installed on your computer,\n"
"or you already installed all of them."
msgstr ""
"Список пакетов пуст. Это означает, что либо нет обновлений для\n"
"пакетов, установленных на вашем компьютере, либо они уже все\n"
"установлены."

#: ../rpmdrake:1
#, c-format
msgid "Emulators"
msgstr "Эмуляторы"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Password:"
msgstr "Пароль:"

#: ../rpmdrake:1
#, c-format
msgid "Software Packages Installation"
msgstr "Установка пакетов программ"

#: ../rpmdrake:1
#, c-format
msgid "in descriptions"
msgstr "в описаниях"

#: ../rpmdrake.pm:1
#, c-format
msgid " failed!"
msgstr " не удалось!"

#: ../rpmdrake:1
#, c-format
msgid "Some additional packages need to be removed"
msgstr "Некоторые дополнительные пакеты должны быть удалены"

#: ../rpmdrake:1
#, c-format
msgid "All packages, by update availability"
msgstr "Все пакеты, по доступности обновлений"

#: ../rpmdrake:1
#, c-format
msgid "Packaging"
msgstr "Пакеты"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Configure media"
msgstr "Настроить источник"

#: ../rpmdrake.pm:1
#, c-format
msgid "United States"
msgstr "Соединенные Штаты"

#: ../rpmdrake.pm:1
#, c-format
msgid "Greece"
msgstr "Греция"

#: ../rpmdrake:1
#, c-format
msgid "GNOME"
msgstr "GNOME"

#: ../rpmdrake:1
#, c-format
msgid "Monitoring"
msgstr "Мониторинг"

#: ../rpmdrake.pm:1
#, c-format
msgid "Costa Rica"
msgstr "Коста-Рика"

#: ../rpmdrake:1
#, c-format
msgid "Some packages can't be installed"
msgstr "Некоторые пакеты не могут быть установлены"

#: ../rpmdrake:1
#, c-format
msgid ""
"The help window has been started, it should appear shortly on your desktop."
msgstr ""
"Окно справки было запущено, скоро оно должно появиться на вашем рабочем "
"столе."

#: ../rpmdrake.pm:1
#, c-format
msgid "No mirror"
msgstr "Нет зеркала"

#: ../rpmdrake.pm:1
#, c-format
msgid "Poland"
msgstr "Польша"

#: ../rpmdrake:1
#, c-format
msgid "Reload the packages list"
msgstr "Перезагрузить список пакетов"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Path or mount point:"
msgstr "Путь или точка монтирования:"

#: ../rpmdrake.pm:1
#, c-format
msgid "Please wait, downloading mirrors addresses from MandrakeSoft website."
msgstr ""
"Пожалуйста, подождите, загружаются адреса зеркал с веб-сайта\n"
"MandrakeSoft"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Choose a mirror..."
msgstr "Выберите зеркало..."

#: ../rpmdrake:1
#, c-format
msgid ""
"Warning: it seems that you are attempting to add so much\n"
"packages that your filesystem may run out of free diskspace,\n"
"during or after package installation ; this is particularly\n"
"dangerous and should be considered with care.\n"
"\n"
"Do you really want to install all the selected packages?"
msgstr ""
"Предупреждение: похоже, что вы пытаетесь добавить слишком\n"
"много пакетов, из-за чего вашей файловой системе не хватит\n"
"свободного места во время или после установки пакетов; это\n"
"чрезвычайно опасно и должно быть учтено с осторожностью.\n"
"\n"
"Вы действительно хотите установить все выбранные пакеты?"

#: ../rpmdrake:1
#, c-format
msgid "Selected size: %d MB"
msgstr "Выбранный размер: %d МБ"

#: ../rpmdrake:1
#, c-format
msgid "Please wait, reading packages database..."
msgstr "Пожалуйста, подождите, читается база пакетов..."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Add a medium"
msgstr "Добавить источник"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Update medium"
msgstr "Обновить источник"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid ""
"In order to save the changes, you need to insert the medium in the drive."
msgstr "Чтобы сохранить изменения, вам необходимо вставить носитель в привод."

#: ../rpmdrake:1
#, c-format
msgid "All packages, by size"
msgstr "Все пакеты, по размеру"

#: ../rpmdrake:1
#, c-format
msgid ""
"There was a problem during the removal of packages:\n"
"\n"
"%s"
msgstr ""
"При удалении пакетов возникла ошибка:\n"
"\n"
"%s"

#: ../rpmdrake.pm:1
#, c-format
msgid "Examining file of medium `%s'..."
msgstr "Изучается файл источника `%s'..."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Path:"
msgstr "Путь:"

#: ../rpmdrake:1
#, c-format
msgid "IRC"
msgstr "IRC"

#: ../rpmdrake:1
#, c-format
msgid "Downloading package `%s' (%s/%s)..."
msgstr "Загружается пакет `%s' (%s/%s)..."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Protocol:"
msgstr "Протокол:"

#: ../rpmdrake:1
#, c-format
msgid "C"
msgstr "C"

#: ../rpmdrake:1
#, c-format
msgid "Other"
msgstr "Другое"

#: ../rpmdrake.pm:1
#, c-format
msgid "Sweden"
msgstr "Швеция"

#: ../rpmdrake:1
#, c-format
msgid "Boards"
msgstr "Настольные"

#: ../rpmdrake.pm:1
#, c-format
msgid "Austria"
msgstr "Австрия"

#: ../rpmdrake:1
#, c-format
msgid "Faqs"
msgstr "ЧАВО"

#: ../rpmdrake.pm:1
#, c-format
msgid "Info..."
msgstr "Информация..."

#: ../rpmdrake:1
#, c-format
msgid "Inspect..."
msgstr "Изучение..."

#: ../rpmdrake.pm:1
#, c-format
msgid "Japan"
msgstr "Япония"

#: ../rpmdrake:1
#, c-format
msgid "Summary: "
msgstr "Сводка: "

#: ../rpmdrake:1
#, c-format
msgid "Backup"
msgstr "Резервирование"

#: ../rpmdrake:1
#, c-format
msgid "Boot and Init"
msgstr "Загрузка и инициализация"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "FTP server"
msgstr "FTP сервер"

#: ../rpmdrake:1
#, c-format
msgid "Remove .%s"
msgstr "Удалить .%s"

#: ../rpmdrake:1
#, c-format
msgid "Importance: "
msgstr "Важность: "

#: ../rpmdrake:1
#, c-format
msgid "WWW"
msgstr "WWW"

#: ../rpmdrake.pm:1
#, c-format
msgid "Unable to create medium."
msgstr "Невозможно создать носитель."

#: ../rpmdrake:1
#, c-format
msgid ""
"The following packages have to be removed for others to be upgraded:\n"
"\n"
"%s\n"
"\n"
"Is it ok to continue?"
msgstr ""
"Следующие пакеты должны быть удалены, чтобы другие могли быть обновлены:\n"
"\n"
"%s\n"
"\n"
"Все в порядке? Можно продолжать?"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid ""
"Welcome to the Software Media Manager!\n"
"\n"
"This tool will help you configure the packages media you wish to use on\n"
"your computer. They will then be available to install new software package\n"
"or to perform updates."
msgstr ""
"Добро пожаловать в Менеджер источников программ!\n"
"\n"
"Этот инструмент поможет вам настроить источники пакетов,\n"
"которые вы хотите использовать на своем компьютере. Затем\n"
"они будут доступны для установки пакетов новых программ или\n"
"для выполнения обновлений."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Medium"
msgstr "Источник"

#: ../rpmdrake:1
#, c-format
msgid "Size: "
msgstr "Размер: "

#: ../rpmdrake:1
#, c-format
msgid "Office"
msgstr "Офис"

#: ../rpmdrake:1
#, c-format
msgid "Everything installed successfully"
msgstr "Все установлено успешно."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Add a parallel group"
msgstr "Добавить параллельную группу"

#: ../rpmdrake:1 ../rpmdrake.pm:1
#, c-format
msgid "Update media"
msgstr "Обновить источник"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Please wait, updating medium..."
msgstr "Пожалуйста, подождите, обновляется носитель..."

#: ../rpmdrake:1
#, c-format
msgid "Installing package `%s' (%s/%s)..."
msgstr "Устанавливается пакет `%s' (%s/%s)..."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Parallel..."
msgstr "Распараллелирование..."

#: ../rpmdrake:1
#, c-format
msgid "Not selected"
msgstr "Не выбрано"

#: ../rpmdrake:1
#, c-format
msgid "in names"
msgstr "в именах"

#: ../rpmdrake:1
#, c-format
msgid "Problem during installation"
msgstr "Во время установки возникла проблема"

#: ../rpmdrake:1
#, c-format
msgid "Terminals"
msgstr "Терминалы"

#: ../rpmdrake:1
#, c-format
msgid "Kernel and hardware"
msgstr "Ядро и оборудование"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Edit"
msgstr "Редактировать"

#: ../rpmdrake:1
#, c-format
msgid "Selected: %d MB / Free disk space: %d MB"
msgstr "Выбрано: %d МБ / Свободно на диске: %d МБ"

#: ../rpmdrake.pm:1
#, c-format
msgid "Australia"
msgstr "Австралия"

#: ../rpmdrake:1 ../edit-urpm-sources.pl:1
#, c-format
msgid "Security updates"
msgstr "Обновления по безопасности"

#: ../rpmdrake.pm:1
#, c-format
msgid "Korea"
msgstr "Корея"

#: ../rpmdrake.pm:1
#, c-format
msgid "Examining remote file of medium `%s'..."
msgstr "Изучается удаленный файл источника `%s'..."

#: ../rpmdrake:1
#, c-format
msgid "in files"
msgstr "в файлах"

#: ../rpmdrake:1
#, c-format
msgid "All packages, by group"
msgstr "Все пакеты, по группе"

#: ../rpmdrake:1
#, c-format
msgid "Kernel"
msgstr "Ядро"

#: ../rpmdrake:1
#, c-format
msgid "Console"
msgstr "Консоль"

#: ../rpmdrake:1
#, c-format
msgid "C++"
msgstr "C++"

#: ../rpmdrake.pm:1
#, c-format
msgid "Netherlands"
msgstr "Нидерланды"

#: ../rpmdrake:1
#, c-format
msgid "Search results (none)"
msgstr "Результаты поиска (нет)"

#: ../rpmdrake:1
#, c-format
msgid "Adventure"
msgstr "Приключения"

#: ../rpmdrake:1
#, c-format
msgid "Cd burning"
msgstr "Запись CD"

#: ../rpmdrake:1
#, c-format
msgid ""
"Welcome to the software installation tool!\n"
"\n"
"Your Mandrake Linux system comes with several thousands of software\n"
"packages on CDROM or DVD. This tool will help you choose which software\n"
"you want to install on your computer."
msgstr ""
"Добро пожаловать в инструмент установки программ!\n"
"Ваша система Mandrake Linux поставляется с несколькими тысячами пакетов\n"
"программного обеспечения на CDROM или DVD. Этот инструмент поможет вам\n"
"выбрать программное обеспечение для установки на ваш компьютер."

#: ../rpmdrake:1
#, c-format
msgid "Stop"
msgstr "Остановить"

#: ../rpmdrake:1
#, c-format
msgid "Biology"
msgstr "Биология"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Please wait, generating hdlist..."
msgstr "Пожалуйста, подождите, создается hdlist..."

#: ../rpmdrake:1
#, c-format
msgid "Mathematics"
msgstr "Математика"

#: ../rpmdrake:1
#, c-format
msgid "Internationalization"
msgstr "Локализация"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Edit a medium"
msgstr "Редактировать источник"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid ""
"There is already a medium by that name, do you\n"
"really want to replace it?"
msgstr ""
"Носитель с таким названием уже существует,\n"
"вы действительно хотите его заменить?"

#: ../rpmdrake:1
#, c-format
msgid ""
"To satisfy dependencies, the following package(s) also need\n"
"to be installed:\n"
"\n"
msgstr ""
"Для удовлетворения зависимостей должны быть установлены\n"
"следующие пакеты:\n"
"\n"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "HTTP server"
msgstr "Сервер HTTP"

#: ../rpmdrake:1
#, c-format
msgid "Unrecoverable error: no package found for installation, sorry."
msgstr "Неисправимая ошибка: к сожалению не найден пакет для установки."

#: ../rpmdrake:1
#, c-format
msgid "Some packages can't be removed"
msgstr "Некоторые пакеты не могут быть удалены"

#: ../rpmdrake:1
#, c-format
msgid ""
"Sorry, the following package(s) can't be selected:\n"
"\n"
"%s"
msgstr ""
"Извините, но следующие пакеты не могут быть выбраны:\n"
"\n"
"%s"

#: ../rpmdrake.pm:1
#, c-format
msgid "Finland"
msgstr "Финляндия"

#: ../rpmdrake:1
#, c-format
msgid "X11 bitmap"
msgstr "X11 bitmap"

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Media limit:"
msgstr "Предел источника:"

#: ../rpmdrake:1
#, c-format
msgid "More information on package..."
msgstr "Дополнительная информация о пакете..."

#: ../edit-urpm-sources.pl:1
#, c-format
msgid "Save changes"
msgstr "Сохранить изменения"

#: ../rpmdrake:1
#, c-format
msgid "Instant messaging"
msgstr "Обмен мгновенными сообщениями"

#: ../rpmdrake:1
#, c-format
msgid "News"
msgstr "Новости"

#. -PO: Keep it short, this is gonna be on a button
#: ../rpmdrake:1
#, c-format
msgid "More info"
msgstr "Дополнительно"

#: ../rpmdrake:1
#, c-format
msgid "Computer books"
msgstr "Компьютерные книги"

#: ../rpmdrake:1
#, c-format
msgid "Search"
msgstr "Поиск"

#: ../rpmdrake.pm:1
#, c-format
msgid ""
"I can't find any suitable mirror.\n"
"\n"
"There can be many reasons for this problem; the most frequent is\n"
"the case when the architecture of your processor is not supported\n"
"by Mandrake Linux Official Updates."
msgstr ""
"Невозможно найти какое-либо подходящее зеркало.\n"
"\n"
"Причин, вызвавших эту проблему, может быть несколько; наиболее\n"
"частым является случай, когда архитектура вашего процессора не\n"
"поддерживается Официальными Обновлениями Mandrake Linux."

#: ../rpmdrake.pm:1
#, c-format
msgid "Spain"
msgstr "Испания"

#: ../rpmdrake:1
#, c-format
msgid "Already existing update media"
msgstr "Уже существующий источники обновления"

#: ../rpmdrake:1
#, c-format