#!/usr/bin/perl # # Copyright (C) 2001-2005 by Mandriva # DUPONT Sebastien # Damien Chaumette # Thierry Vignaud # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # drakfont Future Overview # - Fonts import: # pfb ( Adobe Type 1 binary ) # pfa ( Adobe Type 1 ASCII ) # ttf ( True-Type ) # pcf.gz # Speedo # and Bitmap (PCF, BDF, and SNF) # - Features # - Install fonts from any directory # - Get windows fonts on any vfat partitions # - Get fonts on any partitions. # - UN-installation of any fonts (even if not installed through drakfont) # - Support # - Xfs # - ghostscript & printer # - Staroffice & printer # - abiword # - netscape # - Koffice, Gnumeric, ... studying # - all fonts supported by printer # - anti-aliases by RENDER in Xfree86 .... # supported by KDE. # will be supported by gnome 1.2. # Visual Interface: # Window interface: # - Fontselectiondialog widget # - Command buttons under Fontselectiondialog (like the actual frontend). # Commands buttons: # - import from windows partition. # import from all fat32 partitions and look for winnt/windows/font # and import all (delete doubles) but do not import if they already exist. # - import from directory # look to see if each font exists and do not delete the original. # (replace all, no, none) # expert options: # specify the directory, and look to see if it exists before # if it exists ask: (replace all, no, none) # - uninstall with list per font type # Expert additional switch # - option support: ghostscript, Staroffice, etc... # check-button. (by default all check) # - Printer Application Fonts Support... # check-button. (by default all check) # # TODO: # - Speedo and Bitmap (PCF, BDF, and SNF) # # REQUIRE: # - font-tools.*.mdk.i586.rpm # # USING: # - pfm2afm: by Ken Borgendale: Convert a Windows .pfm file to a .afm (Adobe Font Metrics) # - type1inst: by James Macnicol: type1inst generates files fonts.dir fonts.scale & Fontmap. # - ttf2pt1: by Andrew Weeks, Frank Siegert, Thomas Henlich, Sergey Babkin convert ttf font files to afm and pfb fonts # # # directory to install fonts /usr/X11R6/lib/X11/fonts/ # -->> /usr/X11R6/lib/X11/fonts/drakfont use strict; use diagnostics; use lib qw(/usr/lib/libDrakX); use standalone; #- warning, standalone must be loaded very first, for 'explanations' use ugtk2 qw(:create :dialogs :helpers :wrappers); use common; require_root_capability(); $ugtk2::wm_icon = "drakfont"; # global variables needed by each functions my $xlsfonts = 0; my $windows = 0; my $replace; my $so = 1; my $gs = 1; my $abi = 1; my $printer = 1; my $mode = -1; my @application; my @install; my @uninstall; my $interactive; my $dialog; my $pbar; my $pbar1; my $pbar2; my $pbar3; my $window1; my $model; my $list; my $list_all_font_path; my $left_list; my $right_list; my $left_model; my $right_model; foreach (@ARGV) { /--list|-l/ and $list_all_font_path = 1, $mode = -1; /--xls_fonts/ and $xlsfonts = 1, $mode = -1; /--windows_import|-wi/ and $windows = 1, $mode = -1; /--replace|-r/ and $replace = 1, $mode = -1; /--application/ and $mode = 0, next; $mode == 0 and push @application, $_; /--install/ and $mode = 1, next; $mode == 1 and push @install, $_; /--uninstall/ and $mode = 2, next; $mode == 2 and push @uninstall, $_; } foreach my $i (@application) { if ($i =~ /so/i) { if ($gs != 2) { $gs = 0 } $so = 2; } if ($i =~ /gs/i) { if ($so != 2) { $so = 0 } $gs = 2; } } # PATH and binary full path #my $xfs_conffile = '/etc/fonts/fonts.conf'; my $drakfont_dir = '/usr/X11R6/lib/X11/fonts/drakfont'; my $ttf2pt1 = '/usr/sbin/ttf2pt1'; my $pfm2afm = '/usr/sbin/pfm2afm'; my $type1inst = '/usr/sbin/type1inst'; my $chkfontpath = '/usr/sbin/chkfontpath'; # mkttfdir only knows about iso-8859-1, using ttmkfdir -u instead -- pablo my $ttmkfdir = '/usr/sbin/ttmkfdir'; my $fccache = '/usr/bin/fc-cache'; my @font_list; # list of fonts to install my @installed_fonts; # list of installed fonts my @installed_fonts_path; # list of path included in xfs my @installed_fonts_full_path; # full path list of fonts to uninstall sub list_fontpath() { foreach (grep { /\d+:\s/ } `$chkfontpath -l`) { chomp; s/\d+:\s//gi; s/:\w*$//gi; push @installed_fonts_path, $_; } } sub chk_empty_xfs_path() { foreach my $tmp_path (@installed_fonts_path) { if (every { /^fonts/ || /^type/ } all($tmp_path)) { system("$chkfontpath -r $tmp_path ") or print "PERL::system command failed during chkfontpath\n"; } } } sub search_installed_fonts() { list_fontpath(); interactive_progress($pbar, 0.1, N("Search installed fonts")); push @installed_fonts, all($_) foreach @installed_fonts_path; interactive_progress($pbar, 0.1, N("Unselect fonts installed")); } sub search_installed_fonts_full_path() { list_fontpath(); foreach my $i (@installed_fonts_path) { foreach my $j (all($i)) { push @installed_fonts_full_path, "$i/$j"; } } } sub search_windows_font() { foreach my $fstab_line (grep { /vfat|smbfs|ntfs/ } cat_('/etc/mtab')) { my $win_dir = (split('\s', $fstab_line))[1]; my @list_fonts_win = all("$win_dir/windows/fonts"); my @list_fonts_winnt = all("$win_dir/winnt/fonts"); my $nb_dir = @list_fonts_win + @list_fonts_winnt; foreach ([ \@list_fonts_win, "windows" ], [ \@list_fonts_winnt, "winnt" ]) { foreach my $i (@{ $_->[0] }) { if ($interactive) { if ($nb_dir) { progress($pbar, 0.25 / $nb_dir, N("parse all fonts")); } else { err_dialog(N("Error"), N("No fonts found")); return 0; } } !$replace && any { /$i/ } @installed_fonts and next; any { /$i$/ } @font_list or push @font_list, "$win_dir/$_->[1]/fonts/$i"; } } $interactive && $nb_dir and progress($pbar, 1, N("done")); } if (!@font_list) { print "drakfont:: could not find any font in /win*/fonts \n"; $interactive and err_dialog(N("Error"), N("Could not find any font in your mounted partitions")); return 0; } 1; } my @font_extensions = qw(ttf pfa pfb pcf pcf.gz pfm gsf); sub is_a_font($) { my ($file) = @_; any { $file =~ /\Q.$_\E$/i } @font_extensions; } # Optimisation de cette etape indispensable sub search_dir_font() { foreach my $fn (@install) { my @font_list_tmp; if (!(-e $fn)) { print "$fn :: no such file or directory \n" } else { if (-d $fn) { foreach my $i (all($fn)) { if (is_a_font($i)) { push @font_list_tmp, $i; foreach my $i (@font_list_tmp) { !$replace && any { /$i/ } @installed_fonts and next; any { /$i/ } @font_list or push @font_list, "$fn/$i"; } } } } elsif (is_a_font($fn)) { !$replace && any { /$fn/ } @installed_fonts and next; !any { /$fn/ } @installed_fonts and push @font_list, $fn; } } interactive_progress($pbar, 0.50 / @install, N("Reselect correct fonts")); } interactive_progress($pbar, 1, N("done")); !@font_list && $interactive and err_dialog(N("Error"), N("Could not find any font.\n")); } sub search_dir_font_uninstall { my ($fn) = @_; print "Fonts to uninstal: " . $_ . "\n" foreach uniq(@font_list, -d $fn ? (grep { is_a_font($_) } all($fn)) : if_(is_a_font($fn), $fn)); } sub search_dir_font_uninstall_gi() { @font_list = @uninstall; interactive_progress($pbar, 1, N("Search for fonts in installed list")); } sub print_list() { print "Font(s) to Install:\n\n"; print "$_\n" foreach @font_list; } sub dir_created() { return if $::testing; -e $drakfont_dir or mkdir_p($drakfont_dir); -e $drakfont_dir . "/Type1" or mkdir_p($drakfont_dir . "/Type1"); -e $drakfont_dir . "/ttf" or mkdir_p($drakfont_dir . "/ttf"); -e $drakfont_dir . "/tmp" or mkdir_p($drakfont_dir . "/tmp"); -e $drakfont_dir . "/tmp/ttf" or mkdir_p($drakfont_dir . "/tmp/ttf"); -e $drakfont_dir . "/tmp/Type1" or mkdir_p($drakfont_dir . "/tmp/Type1"); -e $drakfont_dir . "/tmp/tmp" or mkdir_p($drakfont_dir . "/tmp/tmp"); } sub convert_fonts { my ($fonts, $converter, $font_type, $o_generate_pfb) = @_; $o_generate_pfb = $o_generate_pfb ? "-b" : ""; foreach my $fontname (@$fonts) { system("cd $drakfont_dir/tmp/tmp && $converter $o_generate_pfb $fontname"); interactive_progress($pbar2, 0.50 / @$fonts, N("%s fonts conversion", $font_type)); } } sub convert_ttf_fonts { my ($fonts, $o_generate_pfb) = @_; convert_fonts($fonts, $ttf2pt1, "TTF", $o_generate_pfb); } sub move_fonts { my ($src_dir, $dest_dir, @extensions) = @_; my @fonts = map { s!.*/!!; $_ } map { glob("$src_dir/*.$_") } @extensions; system("cd $src_dir && mv @fonts $dest_dir") if @fonts; } sub put_font_dir_real { my ($subdir, $command, $progress, $title) = @_; system("cd $drakfont_dir/$subdir && $fccache && $command"); interactive_progress($pbar2, $progress, $title); return "$chkfontpath -a $drakfont_dir/$subdir; rm -f /usr/X11R6/lib/X11/fonts/fonts.cache-1"; } sub put_font_dir() { -e "/usr/share/ghostscript" or do { $gs = 0; print "ghostscript is not installed on your system...\n" }; if (@font_list) { dir_created(); foreach my $i (@font_list) { cp_af($i, $drakfont_dir . "/tmp/tmp"); interactive_progress($pbar1, 1 / @font_list, N("Fonts copy")); } interactive_progress($pbar1, 0.01, N("done")); interactive_progress($pbar2, 0.10, N("True Type fonts installation")); foreach my $font (glob("$drakfont_dir/tmp/tmp/*.TTF")) { my $newfont = $font; $newfont =~ s/\.TTF$/.ttf/; rename($font, $newfont); } system('cd ' . $drakfont_dir . '/tmp/tmp && cp *.ttf ../../ttf; chmod 644 ../../ttf/*ttf'); interactive_progress($pbar2, 0.20, N("please wait during ttmkfdir...")); my $update_chkfontpath = put_font_dir_real("ttf", "$ttmkfdir -u > fonts.dir", 0.10, N("True Type install done")); if ($gs) { convert_ttf_fonts([ glob("$drakfont_dir/tmp/tmp/*.ttf") ], 1); move_fonts("$drakfont_dir/tmp/tmp", "../Type1", qw(afm gsf pfb pfm)); system("cd $drakfont_dir/tmp/Type1 && $type1inst"); interactive_progress($pbar2, 0.1, N("type1inst building")); if ($so) { -e "$drakfont_dir/tmp/Type1/Fontmap" and system("cd $drakfont_dir/tmp/Type1 && cat Fontmap >> `rpm -ql ghostscript | grep Fontmap.GS` "); move_fonts("$drakfont_dir/tmp/Type1", "../../Type1", qw(afm gsf pfb pfm)); } else { system("cd $drakfont_dir/tmp/Type1 && cat Fontmap >> `rpm -ql ghostscript | grep Fontmap.GS` "); move_fonts("$drakfont_dir/tmp/Type1", "../../Type1", qw(afm gsf pfb pfm)); } $update_chkfontpath .= "; " . put_font_dir_real("Type1", $type1inst, 0.05, N("Ghostscript referencing")); } elsif ($so) { convert_ttf_fonts([ glob("$drakfont_dir/tmp/tmp/*.ttf") ]); convert_fonts([ glob("$drakfont_dir/tmp/tmp/*.pfm") ], $pfm2afm, "PFM"); move_fonts("$drakfont_dir/tmp/tmp", "../Type1", qw(afm)); move_fonts("$drakfont_dir/tmp/Type1", "../../Type1", qw(afm)); $update_chkfontpath .= put_font_dir_real("Type1", $type1inst, 0.14, N("type1inst building")); } interactive_progress($pbar2, 1, N("done")); interactive_progress($pbar3, 0.25, N("Suppress Temporary Files")); rm_rf("$drakfont_dir/tmp/"); print "\n\nretarting xfs......\n"; interactive_progress($pbar3, 0.5, N("Restart XFS")); system($update_chkfontpath); system('/etc/rc.d/init.d/xfs restart'); system('xset fp rehash'); interactive_progress($pbar3, 0.30, N("done")); } } sub remove_gs_fonts() { my @Fontmap_new; if (all("$drakfont_dir/remove")) { system(" cd $drakfont_dir/remove && $type1inst"); my @Fontmap_out = cat_("$drakfont_dir/remove/Fontmap"); my $FontmapGS = `rpm -ql ghostscript | grep Fontmap.GS`; chomp($FontmapGS); my @FontmapGS_list = cat_($FontmapGS); foreach my $font_gs (@FontmapGS_list) { my @tmp_list = split(' ', $font_gs); any { /$tmp_list[0]/ } @Fontmap_out or push @Fontmap_new, $font_gs; } print $_ foreach @Fontmap_new; output($FontmapGS, @Fontmap_new); } } sub remove_fonts() { my @list_dir; -e $drakfont_dir . "/remove" or mkdir_p($drakfont_dir . "/remove") if !$::testing; interactive_progress($pbar, 1, N("done")); foreach my $i (@font_list) { local $_ = $i; if (/.pfb$/ || /.gsf$/ || /.pfm$/ || /.pfa$/) { system("mv $_ $drakfont_dir/remove "); } else { next if $::testing; if (/.ttf$/) { rm_rf($_); # rebuild of the fonts.dir and fc-cache files system("cd `dirname $_` && $fccache && $ttmkfdir -u > fonts.dir"); } else { rm_rf($i) } } $i =~ s!/\w*\.\w*!!gi; any { $i } @list_dir or push @list_dir, $i; interactive_progress($pbar1, 1 / @font_list, N("Suppress Fonts Files")); } interactive_progress($pbar1, 0.01, N("done")); -e "/usr/share/ghostscript" and remove_gs_fonts(); foreach my $i (@list_dir) { if (listlength all($i) < 3) { system("chkfontpath -r $i") or print "PERL::system command failed during chkfontpath\n"; } else { system("cd $i && type1inst") or print "PERL::system command failed during cd or type1inst\n"; } interactive_progress($pbar2, 1 / @list_dir, N("Suppress Fonts Files")); } interactive_progress($pbar2, 0.01, N("xfs restart")); system("/etc/rc.d/init.d/xfs restart"); system('xset fp rehash'); -e "/usr/share/ghostscript" and rm_rf("$drakfont_dir/remove") if !$::testing; interactive_progress($pbar2, 0.01, N("done")); } sub license_msg() { print N("Before installing any fonts, be sure that you have the right to use and install them on your system.\n\n-You can install the fonts the normal way. In rare cases, bogus fonts may hang up your X Server.") . "\n"; } sub backend_mod() { $xlsfonts and system("xlsfonts"); $list_all_font_path and system($chkfontpath); if ($windows) { license_msg(); print "\nWindows fonts Installation........\n"; search_installed_fonts(); if (search_windows_font()) { print_list(); put_font_dir(); } print "\nThe End...........................\n"; } if (@install) { license_msg(); print "\nInstall Specifics Fonts...........\n"; search_installed_fonts(); search_dir_font(); print "Font to install: " . $_ . "\n" foreach @font_list; put_font_dir(); print "\nThe End...........................\n"; } if (@uninstall) { print "\nUninstall Specifics Fonts.........\n"; search_installed_fonts_full_path(); if ($interactive) { search_dir_font_uninstall_gi() } else { search_dir_font_uninstall($_) foreach @uninstall } remove_fonts(); print "\nThe End............................\n"; } } sub interactive_mode() { $interactive = 1; $window1 = ugtk2->new('drakfont'); $window1->{rwindow}->signal_connect(delete_event => sub { ugtk2->exit(0) }); if (!$::isEmbedded) { $window1->{rwindow}->set_position('center'); $window1->{rwindow}->set_title(N("DrakFont")); } my $button = {}; my $disable = sub { my ($b) = @_; $button->{$_}->set_sensitive($_ ne $b) foreach keys %$button }; local $::Wizard_no_previous = 1; gtkadd($window1->{window}, gtkpack_(Gtk2::VBox->new(0, 2), if_(!$::isEmbedded, 0, Gtk2::Banner->new("drakfont", N("DrakFont"))), 0, Gtk2::WrappedLabel->new(N("Font List")), 1, Gtk2::FontSelection->new, 0, create_okcancel(my $oc = { ok_clicked => sub { Gtk2->main_quit }, }, undef, undef, '', if_(0, [ N("About"), \&help, 1 ]), [ N("Options"), \&appli_choice, 1 ], [ N("Uninstall"), \&uninstall, 1 ], [ N("Import"), \&advanced_install, 1 ], [ N("Get Windows Fonts"), sub { $windows = 1; import_status(); $windows = 0 }, 1 ], ), ), ); $oc->{ok}->set_label(N("Close")); $disable->('font_list'); $window1->{rwindow}->show_all; $window1->{rwindow}->realize; $window1->main; ugtk2->exit(0); } $list_all_font_path || $xlsfonts || $windows || @install || @uninstall ? backend_mod() : interactive_mode(); sub help() { ugtk2::create_dialog(N("Help"), formatAlaTeX( #-PO: keep the double empty lines between sections, this is formatted a la LaTeX N("Copyright (C) 2001-2002 by Mandriva DUPONT Sebastien (original version) CHAUMETTE Damien VIGNAUD Thierry ") . "\n\n\n" . N("This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.") . "\n\n\n" . N("Thanks: - pfm2afm: by Ken Borgendale: Convert a Windows .pfm file to a .afm (Adobe Font Metrics) - type1inst: by James Macnicol: type1inst generates files fonts.dir fonts.scale & Fontmap. - ttf2pt1: by Andrew Weeks, Frank Siegert, Thomas Henlich, Sergey Babkin Convert ttf font files to afm and pfb fonts "))); } sub appli_choice() { dialog(N("Options"), [ 0, N("Choose the applications that will support the fonts:"), 0, Gtk2::WrappedLabel->new(N("Before installing any fonts, be sure that you have the right to use and install them on your system.\n\nYou can install the fonts the normal way. In rare cases, bogus fonts may hang up your X Server.")), (map { my ($label, $ref) = @$_; (0, gtkpack_(Gtk2::HBox->new, 0, $label, 1, Gtk2::HBox->new, # BUG: that code never had supported canceling 0, gtksignal_connect(gtkset_active(Gtk2::CheckButton->new, $$ref), toggled => sub { $$ref = $$ref ? 0 : 1 }), ), ); } ([ N("Ghostscript"), \$gs ], [ N("StarOffice"), \$so ], [ N("Abiword"), \$abi ], [ N("Generic Printers"), \$printer ], ), ), ], [ gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => \&exitdialog, ), ], ); } sub font_choice() { my $file_dialog; my $_select_font_msg = N("Select the font file or directory and click on 'Add'"); $file_dialog = Gtk2::FileChooserDialog->new(N("File Selection"), $window1->{real_window}, 'open', N("Cancel") => 'cancel', N("Ok") => 'ok'); # 'select_folder' $file_dialog->set_select_multiple(1); my $filter = Gtk2::FileFilter->new; $filter->set_name(N("Fonts")); $filter->add_pattern("*.$_") foreach @font_extensions; $file_dialog->add_filter($filter); $file_dialog->set_filter($filter); $file_dialog->show; while (my $answer = $file_dialog->run) { if (member($answer, qw(cancel delete-event))) { $file_dialog->destroy; return; } elsif ($answer eq 'ok') { my @files = $file_dialog->get_filenames; foreach my $file_name (difference2(\@files, \@install)) { push @install, $file_name; $model->append_set(undef, [ 0 => $file_name ]); } $file_dialog->destroy; return; } } } sub list_remove() { #- TODO : multi-selection my ($treeStore, $iter) = $list->get_selection->get_selected; return unless $iter; my $to_remove = $treeStore->get($iter, 0); my ($index) = map_index { if_($_ eq $to_remove, $::i) } @install; splice @install, $index, 1; $treeStore->remove($iter); } sub exitdialog() { Gtk2->main_quit } sub dialog { my ($title, $widgets, $buttons, $o_main_loop) = @_; $dialog = _create_dialog($title, { transient => $window1->{real_window} }); $dialog->signal_connect(delete_event => \&exitdialog); gtkpack_($dialog->vbox, @$widgets); gtkpack($dialog->action_area, @$buttons) if $buttons; $dialog->show_all; $window1->{rwindow}->set_sensitive(0); if ($o_main_loop) { gtkflush(); $o_main_loop->(); } else { Gtk2->main; } $dialog->destroy if $dialog; undef $dialog; $window1->{rwindow}->set_sensitive(1); } sub advanced_install() { my $button; $model = Gtk2::TreeStore->new("Glib::String"); $list = Gtk2::TreeView->new_with_model($model); $list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $list->set_headers_visible(0); $list->get_selection->set_mode('browse'); $list->set_rules_hint(1); $model->signal_connect("row-inserted" => sub { $button and $button->set_sensitive(1) }); $model->signal_connect("row-deleted" => sub { $button and $button->set_sensitive($model->get_iter_first) }); dialog(N("Import fonts"), [ 1, create_scrolled_window($list) ], [ gtksignal_connect(Gtk2::Button->new(N("Add")), clicked => \&font_choice), gtksignal_connect(Gtk2::Button->new(N("Remove Selected")), clicked => \&list_remove), gtksignal_connect($button = gtkset_sensitive(Gtk2::Button->new(N("Install fonts")), 0), clicked => sub { $dialog->destroy; undef $dialog; import_status() if @install; }), gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => \&exitdialog), ], ); } sub list_to_remove() { #my @files_path = grep(!/fonts/, all($current_path)); garbage ? gtkflush(); my (@tux) = $left_list->get_selection->get_selected_rows; #- get tree & paths push @uninstall, map { $left_model->get($left_model->get_iter($_), 0) } @tux; #push @uninstall, $current_path . "/" . $files_path[$_] foreach @number_to_remove; garbage ? show_list_to_remove(); } sub show_list_to_remove() { my $model = Gtk2::TreeStore->new("Glib::String"); my $list = Gtk2::TreeView->new_with_model($model); $list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $list->set_headers_visible(0); $list->get_selection->set_mode('browse'); $list->set_rules_hint(1); $model->append_set(undef, [ 0 => $_ ]) foreach @uninstall; dialog(N("Uninstall"), [ 1, gtkpack_(Gtk2::HBox->new(0, 4), 1, create_scrolled_window($list)), ], [ gtksignal_connect(Gtk2::Button->new(N("click here if you are sure.")), clicked => sub { import_status_uninstall(); exitdialog() }), gtksignal_connect(Gtk2::Button->new(N("here if no.")), clicked => \&exitdialog ), ], ); } sub uninstall() { #- TODO : add item to right list with gtksignal_connect @install = (); @installed_fonts_path = (); list_fontpath(); chk_empty_xfs_path(); #- left part $left_model = Gtk2::TreeStore->new("Glib::String"); $left_list = Gtk2::TreeView->new_with_model($left_model); $left_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $left_list->set_headers_visible(0); $left_list->set_rules_hint(1); $left_list->get_selection->set_mode('multiple'); $left_model->append_set(undef, [ 0 => $_ ]) foreach @installed_fonts_path; #- right part $right_model = Gtk2::TreeStore->new("Glib::String"); $right_list = Gtk2::TreeView->new_with_model($right_model); $right_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $right_list->set_headers_visible(0); $right_list->get_selection->set_mode('multiple'); $right_list->set_rules_hint(1); dialog(N("Uninstall"), [ 1, gtkpack_(Gtk2::HBox->new(0, 4), 1, create_scrolled_window($left_list), #1, create_scrolled_window($right_list) ), ], [ gtksignal_connect(Gtk2::Button->new(N("Unselected All")), clicked => sub { $left_list->get_selection->unselect_all } ), gtksignal_connect(Gtk2::Button->new(N("Selected All")), clicked => sub { $left_list->get_selection->select_all } ), gtksignal_connect(Gtk2::Button->new(N("Remove List")), clicked => sub { exitdialog(); list_to_remove() }), gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => \&exitdialog), ], ); } sub import_status() { $pbar = Gtk2::ProgressBar->new; $pbar1 = Gtk2::ProgressBar->new; $pbar2 = Gtk2::ProgressBar->new; $pbar3 = Gtk2::ProgressBar->new; dialog(N("Importing fonts"), [ 0, create_packtable({ col_spacings => 10, row_spacings => 50 }, [ "", "" ], [ N("Initial tests"), $pbar, $pbar->set_text(' ') ], [ N("Copy fonts on your system"), $pbar1, $pbar1->set_text(' ') ], [ N("Install & convert Fonts"), $pbar2, $pbar2->set_text(' ') ], [ N("Post Install"), $pbar3, $pbar3->set_text(' ') ], ), ], [], \&backend_mod, ); } sub import_status_uninstall() { $pbar = Gtk2::ProgressBar->new; $pbar1 = Gtk2::ProgressBar->new; $pbar2 = Gtk2::ProgressBar->new; dialog(N("Importing fonts"), [ 0, create_packtable({ col_spacings => 10, row_spacings => 50 }, [ "", "" ], [ "", "" ], [ N("Initial tests"), $pbar, $pbar->set_text(' ') ], [ N("Remove fonts on your system"), $pbar1, $pbar1->set_text(' ') ], [ N("Post Uninstall"), $pbar2, $pbar2->set_text(' ') ], ), ], [], \&backend_mod, ); } sub progress { my ($progressbar, $incr, $label_text) = @_; $progressbar->set_fraction(min(1, $progressbar->get_fraction + $incr)); $progressbar->set_text($label_text); gtkflush(); } sub interactive_progress { $interactive and progress(@_); } .6f7 73^fGY.'ϱx9cC/PͲ=dz:a"qX%T) s#N?4:Nyt>n'zK)x]hs(zߞ B)WaLɤ G5oCB zBXͭCp@Sɚ7iˋ6u=k8R2:]Çk׳&Q}*w.54 IdJ ~ c3OCk|z'ڭPpeI/Ψ\πkN 4LͫV%1*nԛ˫d>18tB }W1x>:Mz>=A`3?aK/G/=M ȼ c|k^ꇎ#1Q^:}C۫\|2*.@`ho)ƙ7lL^eQhJwVULkN~<'PL Eʣ׶;@vJ52w%HMX9N$UPw@ R]G?p)ʕ Ψ#Q4Q.Rnft˰çȑa!Tǖ@(ګU_hV=92龣4N'Y`GHlCg{Xj&4ZEBS*X.C"Yyux۠)oS {T#j0Xi; 5#V'w E#鸰}Ĉ}Qk9l;2U7h35gU'Q냗cMjCH'Z)a~"$ w1+Gʽ"wSs) ;TzUYμN ʤm]~XԠz, cx@|ޑD꤁Pթv]v%V{||^4h3]|D$%^A1I IvQ I(.Sd/ԣD'!1`SusI k6Fz2Ik0NY",ӿt! f푇߶`pA&Cdy}Յ7:ԙێڠ R/fzԋ1UN34XSٜaVQ!~>Y%Eɋ^(@Q< $ʬQ}Ujǒ >|s?aD@G}- O}W; Η:48; V6W)MudKb-awE]IoiͰ tC)9sD~5ƛ)pIdQz5Gԭ y)O\NU |~!ϙ'S.}abV#wM`&9 bs9#<4F˷,[$ȓhHxCߌ4 \k fO 벾ɋ\@YØMaQ5wh`z;x5Ф<ڌPr ist[h8Ώ /pX\5)6 3>ᢗ4Xh|Y-68aT!BjѴ{}J./2T148S=:#0,z+v/ XO4LzzihƤQîf*iDW E`~Nrzpjt`!ң,JH՘jf,'cS,=h?o*Z[PC=2KTts 3MGG9 vsp"~? NNֽ7bDYJZm>AAh0sj065p@2+c4|L j1D+'=Κ4V -?Q ڡɎ"{d9فu)ԗnHj%福ƶ%УSʍTHBV,*;<^Y|~'&e7q#)f}~W;7F(Q%".85?lNFJL H޹i Ѝ=O4٬+,Gh8ps&FHtl>{&v߼|+Sn݂\5~.)O8@2'4Hő*֖;g\! PJ |# jrN 1mn gzi%O2<<~s"3Cװ'EZlN_&Rn1CL.|,Fg" to?N5d?x skEy#|92&"X١37Bv)XdySSJEc}1 -[V_ŇdR7JׄF>鷩WUq $˙sX'!wŷGϡU+oP*̶5=Ϝ.'w ~oK;S/$˺X2N c;s̡h޽ ?͈TW:d<."M Wgw[ڙu"P ::t]#f@xJɘ~n@.i ͋ pmyFS?c?,`z rAWKwzF0CI9Ʃk`3\dcH&nG؋q(jU N(c!Paf,, 'FV"+I{ă#r'n!i+87pRwgOnp-ĚM WQhjߩhF/P zz>rLiPv=HSuvNNv 't+.f 'QȞ^oeiZ8N%@28iI>u&mp9wx!YM=U Gb>~ZC?6ll͒|q_aYn..(=JmHV62sFHM8u w뱮Y+McI D~GLtvGfS9Q, j*Dw>Q=V`Hl#W\J#&ga6?3JZa|454|AY>6lF=í:vlfqwOā}`u[Ӽ2 s/kaIrGfȱbꄕPa Z4x^ʕ;5U~˰4ȷc*>s(/fe|ͫrGɶBrMvlйHUzԬVilO2Khu;;pAn YhU|ì#Z M":gйU#ݻGE<%xMҶ<7"؅-Tt0`͗p.vqN̮,c$scAroGO7&X0fCo|$p"]e y-U%b[ZN4Y,ȡ~ox>IX OzqD1א[E2#z#&~CF53WqgՀ0r" ZUӡd1OnXsRo*)͗R,dž3$öYѩqD<7w$5ZqT@1 7*=s cP9m:!_Gv)@\>rxAw7\Y[u:~F}Xi&xHL߲G<^X`G}b}WIf#d[ Q_wbe$k?|o|Qr( mOm_Ϩ1]$%\ ^NA  1bb4LB rL1eܦ>Ji晳VNT[KsVV+ : VPNgں4.*uީ I$a% <#ht C/Xa89EQز؄ݢ @Iu=P&ԥR.SfRfNqZ-iTq4 TI&)>aOb6cG.x,{c!Xz#L\~KhEx@cD&ux;ɠONK8Q7]Ci7n(O`Rk*h/Agw-ISGzɗ+Gs;6cRY@^f{[8+f C%Hc[Iu6\Hk*SDZX>X~ ^!vEҨH+InMY'2aQ$8k*+"*_ܯrB;_~,'kͭ[#-Ψ1ew\Uy96/gTHg]oaA =)Go*Df3L N Xuzv=x]%7hˀ",fԶ/j?w2qjq2.MbkWrBhZ1ADp Q&N( >q#̽EՎN$:1umyo%NlLV4 ugR"rїnxl_ P"[Co,ڷ_[z*[tw~Po)(?.2GCác^Dעٙto5kJ;ٴF4+Jzx~^hV6(`즉}ύ&L5Y_Nsd6a:Ƅk45l .,DAy*z$xȁGf_&HS{:OR{U{MS֘h"pKX\BooqD+L6%ܢ&X_h\u;+_p/m Hύ2 \TDc^R+"/EoP^{5ۢn.m,C+{.ڜ)9?t|#Vid]o!$|BaLS)뢁D6=SIt_$%4(TM~Ůoda!-Ub IȄس L ]Jgp3?(!TrI  sx!{oȩLɀQwh_;r_~lLT&yd !䖤nS3.hT-.mQò:6}cꝸe}`*,76qE d ++fR۬j MFzی!JJ77•21$|VZPiNg%~\)53'> Lk!R+ޑ!oaӐH$O͏ 4mB<Վ vu Üeu'|9u߰(<>P>ne4w6etzR)>˅3dCyQ ~vwU8fı+^ff|ps~\KZdY1?E52{|y{+6 n6>H9 ؎9JC< HJz~mB%5sY?b8DGy@$>1T<6k_|R+7Q$V2j;r)tc2>F!ƫ=i&] uMa%=a'_^9jp߲)%ϑŴ0l}AaƁ TǻۀZD%RAk#PY>{qeiY`N^[z2RzdN҆ƽVPO'J?䙺ιǠ'elVȎ E$PQVSI֟ ^V 6rc߮$s}p_VnQ[& ׁUhz^ >m4>΄s/z~YAV_`:w( v>BL!\SE-}:1^"Le 8De[M n#P;ٗt/y|'\]8 cRQjFqA@c. -|_d%ќ@Y!㿦AL};3g,W# -Jҡrf (W~b/Ar Q̐[gk ſ>>*d B˖,‘o9\>+B;gZZBiN<ۍd;A&X}FDDG6А^Q>W0Fn|47e{!CdAoql2 eA[Xdi@яlDƜڡR Yn&wB4uMbni-FzrqXTkݑM+ѕ-%&]ܡ! X$7wC_>ݑm'.t G Nצ9gA|N,b/t ב4Su]MIkvu bV YO0%@ۚ %>UQ9^:#(!O8iE;JyWLxřŰF18zmr}nSHZg!>i]J>C(I"l2kq٨s[7;E`>T҅K$ЁO,2v q!b5cψ#$ƕvyEM+L~ -p;=JF)8r)_6Kbw{2TBIӪdfH;щhYFC ?1,vtMjGb)G p`A ݄2 8@%.ďt5-O޴AI}=|%7Nfuz0ôZi[$,"sӓdkt2Dž>GY3z ;O",Mam0d|sN&ϷMff %R{t.n_3w Av7IH\aqÛե{##I?yLc*F@m7 |4ғbd(l 0$ar +8@$B<;*^kM)O6Q5~'I <^#,VT !I*j1':֑0r񽇭')5N .6*0A ^7TEZiۂ=8??/< ;fA`h)D~+H?gxHV(F&{.EPlWW+|"dA0ܙʶ1\*'h%t&;- U(뢂'fyO}VGVcRHqUi/pLGeHI.OJ*,gkt񋤬%QA;\A]v9}0O뭬;thBތyi}L 0lV}2G>e b1b{~iXhz\7F^m`󓺜0;S|^W4>a΁گd èg_?,qwWIx}-%+֎&d$v'gw嗵wOԋ1Nok6a$w@ueg'cԵxCv.A.v(z"]b2G/AtՠnUP`\NW Ue]]uTDgy\ 5%I^ׇpJ39kYҒr2MNb as3'曋qj#?z~ڶGJ_y0(DqOuPɯoic%ȮTS+ 6TzdnKS_NCXcQMaBqTTYzJӖ>l'5$>gu_!zoMr@N]Z}aDd[xeڶo3B" Ͱcl2{@Ti(pHݬ5Cy,cý_[hdoIR)mIŅL$62Nuϒj/.ux$z蠜4.XƁokH(&5:<lulnXM(\"x7eΒSaehHTfv#(]/"ڠ$U粹4Hc?Y%58&EzyPx11Lab̢T;SF``cBapOI{5oJ+B;6Kj6PB|iW(KmlrWs3 ';ɽkCswJ*'Ur*6BgB hee,:7*yoX: 4s'yE#$d,B`4b]"(ĐNALBoR~HuHmuM}E"[ C&PHx!6kIAvM-X3J I!xeJŔU`cj >D%n(jH7֮FV=P.pMMZBD9gw~_̰cїh>ϵB򲁙LJ:e4(Kj]H'Or|&btz#yhL(ʹoG7FϱM@4x@6WaR-vU k_C}E4l(Y^U/oiV`IlN5T~\,V+C{84.fD$ ^|ڀvUFta>Ь!؟_K[a8tRŌGpIDުomo2ՠښ9]r-Ja 杦&ڹrh+"2ӱtE:oy:b/OTB*m3<տjik{W[j(V0,*0U)KѡT9#ewl|7L[ Q)WG79O8t'x!t$ޕ] ӭDW3;i?FrY̴#W0͏zj4yYpU]vh^N_ pȶ<> ljOC¼RkE20Kv>Ü$tҗg+wDOd&(hF 6Rq'h썟E#6ELEGLr\}:@CX.ipNOɕS}:c5a9JZNwvu(jWFӸ@K EqX EYu]q-i*< k/ Ļ)w`! ~{K"5x((%F'$O 4,5OYW߸Jm_@_Lrf<`o) 6I)P:OH@Ě,nb2睭m[!Q+>d$s"JBӘb.Hy`29FO蜴mmvۿ7 L/:Ƒ8iOu>w`N*jdiفZm.x+p6F7) ,c-W݇C0XRr!Zm( \5 N{oPOb1^o^d0zj|GON͟Gg8G%v\GI.2Q 6a? (@jt~8Ӥ4HXnŊ ׵]J0s|%04>)DfQu5 V./kY]BI~#;&IspVipy)7 F%9ǣtqoLq5}4PE:F@ERl,Kk3&Ǯ4mmhnT.<*8;@hm `y<9Hr20@ doGCgA%^,?VGi%[7OZD\ۍ̚/`{`@?.%4bW ښ`E%u(=! LE)KZ/M"sdV}N4MBnI/V0} o #'wx#AEjZhP0aT|,Rr9lBWꅑƸ؇n\]-*lD2][:?L"o\1ގ<w;o"*E3d8^_-T͎fa Nb`Ǥ_hA5݈PZ(g>@Tђ$b2bd1Ö,ZTUWz=?b𪖰CLs=2n·jk5zmӄ5m1Q^M"RXˡ;Yc/ ՐqACEF&O6p'}0K4 ܂YnEpn9{1$,bf&mŪ`h.7<ߍf0ߗ{ ]7# R`\|Ms: |vtgԀ)Llh:Ո-JêΤ!i\A0QnKkhj'=tpw/yԛ2u A;"/`JtPٶ.@PL>KyicTq;J5q}4 a 2b Je\/ʝ2DNk%vZߟ@]  ۜ7O<|Ωv 7,7`kEJON l&#KfzcagbSe|u$ST!m NR88D6'\ v.`siGl}9nIhR$wM4brJF=\W1E)]8 g$f Ȫ+ {sͿ.,PZN0h$շB2-U/\գs,DƆJ~eDTHU*(OۭC. :nq'kЫ?7BZWn|` 291 m0_b[aӶ83C5~F<ؼFFoMnuRĀnۻO}UZN1?8'k|ʱti_gï9LlF[ 2'+}[rKM`a1ڊ~ON2 QWzH|}u6nG<5.?g?q1w# +w?@zE޾! 7 rcsabَoKwi!C ~LV" aLg>{䒩"lxs'AO<8s< L]y$e-ʬuS,boWy1 DP_ڇ`AÓFxC#*kPӡe\e_4#\:i IGF|[9PPmیDJz Sw*JX_ SmȠa{1sJ5utD&{alGl\]<0 e5D9Y3~K$Nmyk~ {Y}vJ%}Y==u{IŮ)l Ww5;e,'&cHEKsXZ{Fn&,AykƲZ{Dð- ^)(iU,0fupca."(6ڍ4X3xX9F_Iy$pGIk6uA*.(G1Pm1$+%*L ~~Aa]$&&]/X1|30)*n/ eKج]/@B ;/V5(MLt܊2/UjpHyS9گ(8zfƊiϗs54`doж"̬E! /.ԉ-%Zߒq( TTx3y𹙂J'9BdF Yh8wB ( )^mǹ9C1[1:R/#8}fu4CWܯ9(3K rD06ҡaNot,׺F@kFw Eߣ(%96>'gF. C÷:pֶv^.=Z׈rK܃Бϋ.uRszD!Qn9cօ(PdŎ_ֻP} xK*p`lNMI8N8jCybA 4݅ŋTϮb24 ^8ݧQ`@86?+^* f1[pE+m76tg~aUۤ4Quq3k"ԔݘX$k:,0ٿ3 O埯xt}ЃIMqLVpt( C'cOgB!M9 Q(Ѕaզ>'}H:4sU1_eyBو%6m׃b 8y NCh*R"aI<jf2NcZZDUkKGyS=L[Ӻu+b`ϹpVL}D#fOڤΥʒC*ߩ$]?Jj8 *Ѭ"-܉g<\3~P+b[:oaCl4|iiVS$Lb2.6kFeZe8a".'ZĄ@P Qc׍Ұ[ JKsG8SVWÿo~ osH]K1-BTHdbg}{5[>2VA<] _˺45VV0 2#GQ `DQ2w4gG8BUQz7@|N`9Ov9ong9 &"*~Q)| KAGTmĪgQLU%HqY#Wew3YxbX(GI&yZGw#:9Tx!$v-U~c9pmwfq:G t(Ye^e/3~N=L,A%q(cÁ9heYGn:c[)ď7j~mE1N=4je,^hF/p^9őEɱvVB :Qa޳/Ǥb~ )@GlwȖ d_ l$6ѻ'<;ToZ@wU\#Ljc T3doT,ScϵNLyrJ>wCm5т%ذ5t1:u1oXL ȌJA*%}7H)2˼l8`>X'2)A+Kjg@T $ bLD)DS-:;VX)9ƽvۈ8!u8!-˚k|G_Q6zOjԛ(;䦙d`t-d^.۱׍~ǎڿܾ hGCy_t $K2^!U p۟]"e5P2̓d˗ 7nhiB;n@J6/*k74GD85qz>yM!Ƌ2"K8ox[e*O!N?{s 'a:Mm1f 9%r;^iQBYJ$rЯR:rбZ&@5lm,,C &6ms͂ϹؕļIv(ͧeY`*us[p2 )bC_4Ќ Ȋt.tj<@IGVE8Sօk.Z ~z: ,q"Qu:Z!i nUXZx [tсGq[\+Q !a}hپҡLˊIfT=YΞQi$Ô(t%n» el9|TMp ̫ _zIL5gCy6 2+2Al_VػE/:ܽ)Zd&ybr/6beƧ(:/| 6Zir;u )[}AyKדf/0xN#upbl=`fڗpiaM3A2 )s.x!"='KӂN.?9c0KR˸4LkFE y ^dG4R-he(ςzR>VIkT8(Bݚl$_|WdLQ)lЏuP@W#j< , _#UPۂcCxw֟SDzӆ5ZO{&Iݲ?dQMR*Xrbpwù>yFr ocч]]RzW/Vxa3))duЅkCž!*LiVᛁ)YO9ݦVs䙕6qMMsDo|`Vu$;\&z3ԾH<&H^gPT[%[LpIsi4e?Eר*qCRr"O"R<;ZZ_alf+NJEi gB5Rϯ;t@[ef*wcTBEf~32zB02hifn47($L(Ll{)!ExrU LO!{*>N6|w5rsmqi "{L˚MEB D I̠@4ĄNB &üA\Ft_'>jڄؚ陝~lOa kAcgqz*dZp(X g|2\HTF= +Bjk=&ެ $jlxnRsj6mlIĨ d(50@ iZWyA~|c%7ުSSCm@/$Ԛ Ը+"Y+VIՋ$wMQ6n`6GS.jD}۱9.,#W_v'G*23}<)9]&9!|hQھD/ߊ?Y~:'HxU ~~ J;`pTGDGYCe߭ȖXQ!9^ w 4vٞHE1}hbv<0LjnaW#車`ꢯGs sC?o;6Xn-v+Se>tbHķQDa=4M.TXw]s`dߛWY6ߍB7c Uk!= !@1fztDZ t5~*C76{tzF@":ADۓ=BDŽ,ހq!Pq7rSC"@)#O}fSJ3Q_o b)PK[M8zLe&zh#RøL@VNecyGHwl~G.+zuzf UjL%f^\d|)|HS[d+71b-UA]igђ$d̡/*pP #ث64B&6,;~1ƳwQ=+vH*+֪%CVT20EbK0G 5wxk2N(#JL1߿&)]rW;.p,d0["Uh91v#1pKF@g]gNZprL8ߕZN'amz@+pqq%DMCץC)}XJPj ̡Ԑ¡vF)ɷ-|5-[rP:a&?u#8uߜJ(ȼzCa6!abKF!㚪+ z]qPĚ`//Da[T+`I"Xk i9dhkCGfAA#\*g/ A*Do+bsF2咐;mphO*bZ=,RP@~@THܬf@ͷnjiR DltH</h"akGwɷ!&iўMiŅ ^DMS !v42r!G-Ҡe Fp-Sq;xjӗ":8yWWLw bx:5h:AU1uJ " nD`(px^m{s}i)B[#r@d5%ۛw3l<DWu3D`Kj'pDR^a0QY4*Ld+j3CVxD-R`9|C48P=l+C〴6%9[Qʝb:oLːQAjK| :E4(WJu&_ADT8 1O5Ӳyz2 "N.*sA^LX*lCF~j@)ֆvT7Ƕ^^%W /l{ǽf*{X@7cH{bR0psNhcSI冫jqMnP.eȄSxQ9R[f/ 8j9z& sZ DR ں cFlYNlLGIit_Ql5IHRTx1یW[cQ#&z*O#R2Tiz?XU mXboszq΃jp/1(5LQ|VaxtX mݕNRlkg8 :0Igf(bE?fb ٕ巣sHʴ̂h5L. C8qg^rӝ,D??)OkB}YL{}}^CisQ~rLSir*s&}y%,>g _˱2NjM1ނN%ߛ\6OL3 8EXV;ua,3 CBU;[ƏXn?ʺ" իLC&cuNՠ)KM5Ul/H>kԝΥǫM6U鯃N{0`Tm`w&ix3q PQd*J_J## {X>U$ ]=dbC*mr3.zhi7\b(8+L,!uzkdW]A/T[@s7sJdz"UvvЊ%R=xTv9pa¬t:.F>,ԕ }!sv,8|*qXdBҰy̨-mKןEd^.aXCeUWeʐH׳ ڔ}ɧxF