#!/usr/bin/perl use lib qw(/usr/lib/libDrakX); use standalone; use MDK::Common; use Gtk; use interactive; use ugtk qw(:helpers :wrappers); init Gtk; #- convenience variables for true and false my $false = 0; my $true = 1; #- this part is embedded management $::isEmbedded = ($::XID, $::CCPID) = "@ARGV" =~/--embedded (\S*) (\S*)/; if ($::isEmbedded) { print "EMBED\n"; print "XID : $::XID\n"; print "CCPID : $::CCPID\n"; } my $in = 'interactive'->vnew('su', 'default'); local $_ = join '', @ARGV; /-h/ and die _("no help implemented yet.\n"); /-version/ and die 'version: $Id$'."\n"; my $window = $::isEmbedded ? new Gtk::Plug ($::XID) : new Gtk::Window ("toplevel"); $window->signal_connect(delete_event => sub { $::isEmbedded ? kill(USR1, $::CCPID) : &CloseAppWindow }); #- verification of package image magik if(!$in->do_pkgs->is_installed('ImageMagick')){ $in->ask_okcancel(_("Error"),_("package 'ImageMagick' is required for correct working.\nClick \"Ok\" to install 'ImageMagick' or \"Cancel\" to quit")) and $in->do_pkgs->install('ImageMagick') or $::isEmbedded ? kill(USR1, $::CCPID) : &CloseAppWindow ; } #- application vars my $tmp_path = '/tmp/draksplash/'; ! -d $tmp_path and mkdir($tmp_path); my $thm_path = '/usr/share/bootsplash/themes/'; my $thm_conf_path = '/etc/bootsplash/themes/'; my $prev_window; my $pix; my $boot_conf_path = '/etc/bootsplash/themes/'; my %font_size = ('h'=>16,'w'=>8); my %theme = ('name'=>'new_theme', 'res' =>{'res'=>'800x600', 'h'=>'600', 'w'=>'800' }, 'boot_conf'=>{ 'tx' => 0 , 'ty' => 0 , 'tw' => 0 , 'th' => 0 , 'px' => 0 , 'py' => 0 , 'pw' => 0 , 'ph' => 0 , 'pc' => '0x21459d', }, 'boot_img'=> '', ); my %scale_size = ('tx'=> ($theme{'res'}{'w'} / $font_size{'w'}), 'ty'=> ($theme{'res'}{'h'} / $font_size{'h'}), 'tw'=> ($theme{'res'}{'w'} / $font_size{'w'}), 'th'=> ($theme{'res'}{'h'} / $font_size{'h'}), 'px'=> $theme{'res'}{'w'}, 'py'=> $theme{'res'}{'h'}, 'pw'=> $theme{'res'}{'w'}, 'ph'=> $theme{'res'}{'h'}, ); my %first = ('frame'=>new Gtk::Frame(_("first step creation")), 'widget'=>{ 'label'=> { 'res'=>_("final resolution"), 'file'=>_("choose image file"), 'name'=>_("Theme name") }, 'button'=>{ #'boot_conf'=>_("Make bootsplash step 2"), #'lilo_conf'=>_("Go to lilosplash configuration"), 'file'=>_("Browse"), }, 'combo'=> {'res'=>['800x600', '1024x768', '1280x1024'], 'name'=>[ $theme{'name'} , &giv_exist_thm] }, ,}, 'pos'=>[ 'name', 'res', 'file', 'boot_conf', #'save', #'kill' ], ); my %boot_conf_frame = ('frame' => new Gtk::Frame( _("Configure bootsplash picture") ), 'widget'=> { 'label' => { 'tx'=> _("x coordinate of text box\nin number of character"), 'ty'=> _("y coordinate of text box\nin number of character"), 'tw'=> _("text width"), 'th'=> _("text box height"), 'px'=> _("the progress bar x coordinate\nof its upper left corner"), 'py'=> _("the progress bar y coordinate\nof its upper left corner"), 'pw'=> _("the width of the progress bar"), 'ph'=> _("the heigth of the progress bar"), 'pc'=> _("the color of the progress bar") }, #- must set scale values to true to get them created by mk_frame 'scale' => {'tx'=> 1, 'ty'=> 1, 'tw'=> 1, 'th'=> 1, 'px'=> 1, 'py'=> 1, 'pw'=> 1, 'ph'=> 1, }, 'button' => { #'annul'=> _("Go back"), 'prev'=>_("Preview"), 'kill'=>_("Quit"), 'save'=>_("Save theme"), 'pc'=> _("Choose color"), }, 'check' => { 'logo' => _("Display logo on Console" ), 'quiet'=> _("Make kernel message quiet by default"), }, }, 'pos'=> [ 'tx 1' , 'ty 1' , 'tw 1' , 'th 1' , 'px 1' , 'py 1' , 'pw 1' , 'ph 1' , 'pc' , 'logo', 'quiet', 'annul', 'prev', 'save' , 'kill', ], ); #- var action is used to hide/show the correct frame my @action_frame = ( \%boot_conf_frame , \%first); my $VB2 = new Gtk::VBox(0,5); &mk_frame(\$VB2,\%first); #****************************- Signal event actions #- change resolution $first{'widgets'}{'combo'}{'res'}->entry->signal_connect( changed => sub { $theme{'res'}{'res'} = $first{'widgets'}{'combo'}{'res'}->entry->get_text; ($theme{'res'}{'w'},$theme{'res'}{'h'}) = $theme{'res'}{'res'} =~ /([^x]+)x([^x]+)/; &set_scale_size; $boot_conf_frame{'frame'}->destroy ; $boot_conf_frame{'frame'} = new Gtk::Frame(_("Configure bootsplash picture") ); &make_boot_frame; $first_vbox->add($boot_conf_frame{'frame'}); member( $theme{'name'}, &giv_exist_thm) and &thm_in_this_res and &get_this_thm_res_conf or $in->ask_warn(_("Notice"),_("This theme haven't yet any bootsplash in %s !",$theme{'res'}{'res'})); }); #- go to bootsplash configuration step 2 #$first{'widgets'}{'button'}{'boot_conf'}->signal_connect( clicked => sub{show_act(\%boot_conf_frame) } ); #- image file selection for new theme $first{'widgets'}{'button'}{'file'}->signal_connect( clicked =>sub{ my $file_dialog = new Gtk::FileSelection('choose image'); $file_dialog->set_filename( ( $first{'widgets'}{'label'}{'file'}->get ne _("choose image file") )?$first{'widgets'}{'label'}{'file'}->get:'~/' ); $file_dialog->cancel_button->signal_connect( clicked => sub{ $file_dialog->destroy} ); $file_dialog->ok_button->signal_connect( clicked => sub{ $first{'widgets'}{'label'}{'file'}->set_text($file_dialog->get_filename) ; $file_dialog->destroy ;}); $file_dialog->show; }); #- changing theme name $first{'widgets'}{'combo'}{'name'}->entry->signal_connect( changed => sub{ &get_this_thm_res_conf; $theme{'name'} = $first{'widgets'}{'combo'}{'name'}->entry->get_text; }); #************************************************** $first_vbox = new Gtk::VBox(0,5); $first_vbox->add($first{'frame'}); $first_vbox->add($boot_conf_frame{'frame'}); &make_boot_frame; # set window attributes and show it $window->border_width( 5 ); $window->add($first_vbox); $window->set_policy( 0, 1, 1 ); $window->set_position('center'); $window->show_all(); #&show_act(\%first); # Gtk event loop main Gtk; # Should never get here exit( 0 ); ### Callback function to close the window sub CloseAppWindow{ Gtk->exit( 0 ); return $false; } #- ====## used funtions ##===== #- Desc => write config file for boot theme and copy image in the right location sub write_boot_thm{ my $w = $in->wait_message('',_("saving Bootsplash theme...")); &set_thm_values; my $logo = ($boot_conf_frame{'widgets'}{'check'}{'logo'}->get_active)?'yes':'no'; my $quiet = ($boot_conf_frame{'widgets'}{'check'}{'quiet'}->get_active)?'yes':'no'; my $globalconf_file = $thm_conf_path.$theme{'name'}.'/global.config'; my $cfg_file = $thm_conf_path.$theme{'name'}.'/cfg/bootsplash-'.$theme{'res'}{'res'}.'.cfg'; #- verify all dir exists or create them -d $thm_conf_path.$theme{'name'} or mkdir($thm_conf_path.$theme{'name'}); -d $thm_conf_path.$theme{'name'}.'/cfg' or mkdir($thm_conf_path.$theme{'name'}.'/cfg'); -d $thm_path.$theme{'name'} or mkdir($thm_path.$theme{'name'}); -d $thm_path.$theme{'name'}.'/images/' or mkdir($thm_path.$theme{'name'}.'/images/'); #- copy image to dest by convert system('convert -scale '.$theme{'res'}{'res'} .' '.$first{'widgets'}{'label'}{'file'}->get.' '.$thm_path.$theme{'name'}.'/images/bootsplash-'.$theme{'res'}{'res'}.'.jpg'); system('/usr/share/bootsplash/scripts/rewritejpeg '.$thm_path.$theme{'name'}.'/images/bootsplash-'.$theme{'res'}{'res'}.'.jpg'); #- write conf files my $cfg_cont = '# This is the configuration file for the '.$theme{'res'}{'res'}.' bootsplash picture # this file is necessary to specify the coordinates of the text box on the # splash screen. # tx is the x coordinate of the text window in characters. default is 24 # multiply width font width for coordinate in pixels. tx='.$theme{'boot_conf'}{'tx'}.' # ty is the y coordinate of the text window in characters. default is 14 ty='.$theme{'boot_conf'}{'ty'}.' # tw is the width of the text window in characters. default is 130 # note: this should at least be 80 as on the standard linux text console tw='.$theme{'boot_conf'}{'tw'}.' # th is the height of the text window in characters. default is 44 # NOTE: this should at least be 25 as on the standard linux text console th='.$theme{'boot_conf'}{'th'}.' # px is the progress bar x coordinate of its upper left corner px='.$theme{'boot_conf'}{'px'}.' # py is the progress bar y coordinate of its upper left corner py='.$theme{'boot_conf'}{'py'}.' # pw is the with of the progress bar pw='.$theme{'boot_conf'}{'pw'}.' # ph is the heigth of the progress bar ph='.$theme{'boot_conf'}{'ph'}.' # pc is the color of the progress bar pc='.$theme{'boot_conf'}{'pc'}.'' ; my $globalconf_cont = '# Display logo on console. LOGO_CONSOLE='.$logo.' # Make kernel message quiet by default. QUIET='.$quiet ; output($globalconf_file, $globalconf_cont); output($cfg_file,$cfg_cont); } #- Desc => read the current bootsplash theme configuration if exist sub get_this_thm_res_conf{ member($first{'widgets'}{'combo'}{'name'}->entry->get_text , &giv_exist_thm) and $theme{'name'} = $first{'widgets'}{'combo'}{'name'}->entry->get_text and &thm_in_this_res(1) and &read_boot_conf; -f $thm_path.$theme{'name'}."/images/bootsplash-".$theme{'res'}{'res'}.".jpg" and $first{'widgets'}{'label'}{'file'}->set_text($thm_path.$theme{'name'}."/images/bootsplash-".$theme{'res'}{'res'}.".jpg"); return 1; } sub read_boot_conf { chdir($thm_conf_path); my $line; if(-f $theme{'name'}.'/cfg/bootsplash-'.$theme{'res'}{'res'}.'.cfg') { open CFG , $theme{'name'}.'/cfg/bootsplash-'.$theme{'res'}{'res'}.'.cfg'; while($line = ){ $line =~ m/^([a-z][a-z])=([^\n]+)/ and $theme{'boot_conf'}{$1} = $2; } close CFG; &set_scale_values; } else { return 0; } } sub set_scale_values{ foreach (keys %{$theme{'boot_conf'}}){ ${$_.'_adj'} and ${$_.'_adj'}->set_value($theme{'boot_conf'}{$_}); } } #- Desc => check if this theme is available in the current resolution else #- change the current resolution or display a ask_warn box #- Args => ø #- return=> (bool) sub thm_in_this_res{ my ($check_res) = @_; (-f $thm_path.$theme{'name'}."/images/bootsplash-".$theme{'res'}{'res'}.".jpg")?return 1 : ($check_res == 1)?return &which_res_exist : return 0 ; } sub which_res_exist{ chdir($thm_path.$theme{'name'}."/images/"); my $is_ok = 0; foreach(@{$first{'widget'}{'combo'}{'res'}}){ -f "bootsplash-$_.jpg" and $is_ok = 1 and $first{'widgets'}{'combo'}{'res'}->entry->set_text($_) and last; } $is_ok == 1 or $in->ask_warn(_("Notice"),_("This theme haven't yet any bootsplash in %s !",$theme{'res'}{'res'})) and return 0; return 1; } #- Desc => retrieve all installed theme #- Args => ø #- Return=> @arr of available theme sub giv_exist_thm{ chdir($thm_path); my @thms_dirs; foreach (glob("*")) { -d $_ && m/^[^.]/ and push @thms_dirs, $_; } return @thms_dirs; } #- Desc =>show only the right frame #- Args => action(str) #- Return=> (bool) sub show_act{ # my ($action) = @_; # foreach (@action_frame){ # if($_ == $action){ # $_->{'frame'}->show_all ; # }else{ # $_->{'frame'}->hide; # } # } } #- Desc => just add tooltips #- Args => name of widget(str) and frame to work on it (\%hash) sub tool_tip{ my ( $name , $ref ) = @_; foreach (keys %{$ref->{'widget'}}){ $_ eq 'tooltip' and next; if($ref->{'widget'}{$_}{$name}){ ! ${$name.'_tip'} and ${$name.'_tip'} = new Gtk::Tooltips(); ${$name.'_tip'}->set_tip($ref->{'widgets'}{$_}{$name}, $ref->{'widget'}{'tooltip'}{$name},''); } } } #- Desc => just prepare widgets for a fram hash #- Args => $box(a Vbox widget to contain all widgets), \%frame (hash with complete definition of the frame) #- Return=> all hash{'widgets'} are created and packed in $box sub mk_frame{ my ( $box , $ref ) = @_; foreach $pos (@{$ref->{'pos'}}){ $pos =~ m/^(\w+)(\s+)?(\w+)?$/; #- open a new hbox ${$1.'hb'} = new Gtk::HBox($3?1:0,5); #- look for label $ref->{'widget'}{'label'}{$1} and $ref->{'widgets'}{'label'}{$1} = new Gtk::Label($ref->{'widget'}{'label'}{$1}) and ${$1.'hb'}->add($ref->{'widgets'}{'label'}{$1}); #- look for scale $ref->{'widget'}{'scale'}{$1} and $ref->{'widgets'}{'scale'}{$1} = new Gtk::HScale( ${$1."_adj"} = new Gtk::Adjustment(0,0,$scale_size{$1},1,10,0)) and ${$1."hb"}->add($ref->{'widgets'}{'scale'}{$1}) and $ref->{'widgets'}{'scale'}{$1}->set_digits(0); ${$1.'_adj'} and ${$1.'_adj'}->set_value($theme{'boot_conf'}{$1}); #- look for combo $ref->{'widget'}{'combo'}{$1} and @popdown = @{$ref->{'widget'}{'combo'}{$1}} and $ref->{'widgets'}{'combo'}{$1} = new Gtk::Combo and ${$1."hb"}->add($ref->{'widgets'}{'combo'}{$1}) and $ref->{'widgets'}{'combo'}{$1}->set_popdown_strings(@popdown); #- look for checkbox $ref->{'widget'}{'check'}{$1} and $ref->{'widgets'}{'check'}{$1} = new Gtk::CheckButton( $ref->{'widget'}{'check'}{$1} ) and ${$1."hb"}->add($ref->{'widgets'}{'check'}{$1}) and $ref->{'widgets'}{'check'}{$1}->set_active(1); #- look for button $ref->{'widget'}{'button'}{$1} and $ref->{'widgets'}{'button'}{$1} = new Gtk::Button($ref->{'widget'}{'button'}{$1}) and ${$1."hb"}->add($ref->{'widgets'}{'button'}{$1}); #- look for tooltips $ref->{'widget'}{'tooltip'}{$1} and &tool_tip($1,\%{$ref}); ${$box}->add(${$1."hb"}); } $ref->{'frame'}->add(${$box}); } #- Desc => take a decimal value between 0 to 255 and return the corresponding hexadecimal value sub dec2hex{ my ($dec) = @_; my @dec_hex = (0,1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'); my $int; my $float; $dec = $dec/16; $int = int($dec); $float = $dec_hex[int(($dec-$int)*16)]; $int = $dec_hex[$int]; return "$int$float"; } #- Desc => prepare and set all signal_connect for boot_frame widget sub make_boot_frame{ $VB = new Gtk::VBox(0,5); &mk_frame(\$VB,\%boot_conf_frame); #- open a color choose box $boot_conf_frame{'widgets'}{'button'}{'pc'}->signal_connect( clicked => sub { $color = new Gtk::ColorSelectionDialog(_("ProgressBar color selection")); $theme{'boot_conf'}{'pc'} =~ m/0x(.{2})(.{2})(.{2})/; my @rgb = map { hex($_)/255 } ($1 ,$2, $3); $color->colorsel->set_color(@rgb);#$theme{'boot_conf'}{'pc'}); $color->cancel_button->signal_connect(clicked=> sub{$color->destroy}); $color->ok_button->signal_connect(clicked=> sub{ @rgb = $color->colorsel->get_color(); @rgb = map ( dec2hex($_*255) , @rgb); $theme{'boot_conf'}{'pc'} = "0x$rgb[0]$rgb[1]$rgb[2]"; $color->destroy; }); $color->show; }); #- quit button $boot_conf_frame{'widgets'}{'button'}{'kill'}->signal_connect( clicked => \&CloseAppWindow); $boot_conf_frame{'widgets'}{'button'}{'save'}->signal_connect(clicked=> sub{ &write_boot_thm }); #- return to first screen #$boot_conf_frame{'widgets'}{'button'}{'annul'}->signal_connect( clicked => sub { show_act( \%first ) } ); #- made a preview $boot_conf_frame{'widgets'}{'button'}{'prev'}->signal_connect( clicked => sub{ if(! -f $first{'widgets'}{'label'}{'file'}->get) { $in->ask_warn(_("Notice"),_("You must choose an image file first!")); return 0; } #- calculation of the 2 angle of text box and progress bar &set_thm_values; my $text_tl = ($theme{'boot_conf'}{'tx'}*$font_size{'w'}).','.$theme{'boot_conf'}{'ty'}*$font_size{'h'}; my $text_br = ($theme{'boot_conf'}{'tw'}*$font_size{'w'}+$theme{'boot_conf'}{'tx'}*$font_size{'w'}).','.($theme{'boot_conf'}{'th'}*$font_size{'h'}+$theme{'boot_conf'}{'ty'}*$font_size{'h'}); my $progress_tl = $theme{'boot_conf'}{'px'}.','.$theme{'boot_conf'}{'py'}; my $progress_br = ($theme{'boot_conf'}{'px'}+$theme{'boot_conf'}{'pw'}).','.($theme{'boot_conf'}{'py'}+$theme{'boot_conf'}{'ph'}); my $w = $in->wait_message('', _("Generating preview ...")); $x++; local $txt_tl_x = $theme{'boot_conf'}{'tx'}*$font_size{'w'}; local $txt_tl_y = $theme{'boot_conf'}{'ty'}*$font_size{'h'}; local $txt_width = $theme{'boot_conf'}{'tw'}*$font_size{'w'}; local $txt_height = $theme{'boot_conf'}{'th'}*$font_size{'h'}; local $prog_tl_x = $theme{'boot_conf'}{'px'}; local $prog_tl_y = $theme{'boot_conf'}{'py'}; local $prog_width = $theme{'boot_conf'}{'pw'}; local $prog_height= $theme{'boot_conf'}{'ph'}; &show_prev($first{'widgets'}{'label'}{'file'}->get,$txt_tl_x,$txt_tl_y,$txt_width,$txt_height,$prog_tl_x,$prog_tl_y,$prog_width,$prog_height); } ); $boot_conf_frame{'frame'}->show_all; # - check scales values are possibly correct #&set_scale_values; foreach my $k ( keys %{$theme{'boot_conf'}}){ $k =~ m/[tp][hwyx]/ and ${$k.'_adj'}->signal_connect(value_changed => sub{ &check_boot_scales($k) }); } # unlink "$tmp_path.prev$x.png"; } #- Desc => set theme values from user entry (scales widgets) sub set_thm_values{ foreach(keys %{$theme{'boot_conf'}}) { m/[tp][hwyx]/ and $theme{'boot_conf'}{$_} = int(${$_.'_adj'}->get_value); } } #- Desc => destroy properly all widget of preview window sub kill_preview{ $prev_window->destroy; undef($prev_window); $prev_canvas->destroy; undef($prev_canvas); undef($prev_pic); undef($prev_pix); } #- Desc => create a new window with a preview of splash screen #- Args => $file (str) full path to preview file sub show_prev{ my ($file,$txt_tl_x,$txt_tl_y,$txt_width,$txt_height,$prog_tl_x,$prog_tl_y,$prog_width,$prog_height) = @_; $prev_window or ($prev_window = new Gtk::Window('toplevel') and $prev_window->set_policy( 0, 1, 1 ) ); #-PO First %s is theme name, second %s (in parenthesis) is resolution $prev_window->set_title(_("%s BootSplash (%s) preview",$theme{'name'},$theme{'res'}{'res'})); $prev_pic = gtkcreate_png_pixbuf($file); $prev_pic->scale_simple($theme{'res'}{'w'},$theme{'res'}{'h'},0); $prev_pix = $prev_pic->render_pixmap_and_mask($prev_pic); ( $prev_canvas and $prev_canvas->isa('Gtk::Widget') ) or ( $prev_canvas = new Gtk::DrawingArea() and $prev_window->add($prev_canvas) ); $prev_canvas->set_usize($theme{'res'}{'w'},$theme{'res'}{'h'}); $prev_canvas->signal_connect( expose_event => sub{ $prev_canvas->window->draw_pixmap( $prev_canvas->style->bg_gc('normal'),$prev_pix,0,0,0,0,$theme{'res'}{'w'},$theme{'res'}{'h'}); $prev_canvas->window->draw_rectangle( $prev_canvas->style->black_gc, $true,$txt_tl_x, $txt_tl_y,$txt_width,$txt_height ); $prev_canvas->window->draw_rectangle( $prev_canvas->style->black_gc, $true, $prog_tl_x,$prog_tl_y,$prog_width, $prog_height ); }); $prev_window ->signal_connect(delete_event => \&kill_preview ); $prev_window->show_all; } #- Desc => define the max size of boot's scales sub set_scale_size{ %scale_size = ('tx'=> ($theme{'res'}{'w'} / $font_size{'w'}), 'ty'=> ($theme{'res'}{'h'} / $font_size{'h'}), 'tw'=> ($theme{'res'}{'w'} / $font_size{'w'}), 'th'=> ($theme{'res'}{'h'} / $font_size{'h'}), 'px'=> $theme{'res'}{'w'}, 'py'=> $theme{'res'}{'h'}, 'pw'=> $theme{'res'}{'w'}, 'ph'=> $theme{'res'}{'h'}, ); } #- Desc => verify that boot's scales widgets are correctly set #- Args => $obj (str) is the scale to check value sub check_boot_scales{ my ($obj) = @_; my $tw = $tw_adj->get_value; my $tx = $tx_adj->get_value; my $th = $th_adj->get_value; my $ty = $ty_adj->get_value; my $pw = $pw_adj->get_value; my $ph = $ph_adj->get_value; my $px = $px_adj->get_value; my $py = $py_adj->get_value; my $max_x = $scale_size{'tw'}; my $max_y = $scale_size{'th'}; my $max_xres = $theme{'res'}{'w'}; my $max_yres = $theme{'res'}{'h'}; $obj eq 'tw' and $max_x < ($tw + $tx) and $tx_adj->set_value($max_x - $tw); $obj eq 'tx' and $max_x < ($tw + $tx) and $tw_adj->set_value($max_x - $tx); $obj eq 'th' and $max_y < ($th + $ty) and $ty_adj->set_value($max_y - $th); $obj eq 'ty' and $max_y < ($th + $ty) and $th_adj->set_value($max_y - $ty); $obj eq 'pw' and $max_xres < ($pw + $px) and $px_adj->set_value($max_xres - $pw); $obj eq 'px' and $max_xres < ($pw + $px) and $pw_adj->set_value($max_xres - $px); $obj eq 'ph' and $max_yres < ($ph + $py) and $py_adj->set_value($max_yres - $ph); $obj eq 'py' and $max_yres < ($ph + $py) and $ph_adj->set_value($max_yres - $py); }