http://www.perlmonks.org?node_id=261772


in reply to Launch from Tk

exec() replaces the current process with a new one. When you call exec from the perl process that's running your Tk program you replace it with the exec'd process. The solution is to fork() and run exec() from the child process.

The only issue I'm not 100% certain about is the handling of the CHLD signal and child exit status, particularly when exec() fails. Hopefully someone with a better grasp of the issues can help clear that up.

Here's a short example:

#!/usr/bin/perl use Tk; sub go { local $SIG{CHLD} = 'IGNORE'; # don't wait for child # exit status. avoids # zombies. die "fork failed: $!" unless defined($pid = fork); return if $pid; exec("xterm"); warn "exec failed: $!"; CORE::exit(1); } $m = tkinit; $m->Button(-text=>"Foo",-command=>sub{print"Foo\n"})->pack; $m->Button(-text=>"Go",-command=>\&go)->pack; MainLoop;

Replies are listed 'Best First'.
Re: Re: Launch from Tk
by aplonis (Pilgrim) on May 30, 2003 at 16:54 UTC
    That seems to work. Most helpful, thank you. Here is the updated PerlTk program (tested on NetBSD 1.6.1_STABLE)
    #!/usr/pkg/bin/perl 
    # gus_kbds.pl version 1.01
    # Copyright (c) 2003 by Gan Uesli Starling
    
    use Tk;
    use strict;
    
    use vars qw( 
      $programo_1 
      $xmodmap_verda $xmodmap_alia 
      $e_feedback $feedback 
      $pid_1
    );
    
    sub set_defaults {
     $xmodmap_verda = "/home/aplonis/.Xmodmap_verda";
     $xmodmap_alia = "/usr/X11R6/lib/X11/etc/xmodmap.std";
     $programo_1 = "xterm -u8 -fn -misc-fixed-medium-r-normal--14-130-75-75-c-70-iso10646-1 -name FOO";
    }
    
    set_defaults; # Do right away.
    
    # Give initial feedback hint.
    $feedback = "Premu butonon.";
    
    # The main window.
    my $mw_kbd = MainWindow->new(-title=>'Klavo-sxangxilo');
    
    # Frame for buttons.
    my $fm_kbds = $mw_kbd->Frame(-relief=>'flat',-borderwidth=>5);
    my $bn_tajpu = $fm_kbds->Button( 
      -relief=>'raised',-text=>"Tajpu",-command=>\&tajpu,-width=>5,
      -background=>'gray',-activebackground=>'orange');
    my $bn_eo = $fm_kbds->Button( 
      -relief=>'raised',-text=>"Verda",-command=>\&kbd_eo,-width=>5,
      -background=>'gray',-activebackground=>'green');
    my $bn_en = $fm_kbds->Button(
      -relief=>'raised',-text=>"Alia",-command=>\&kbd_en,-width=>5,
      -background=>'gray',-activebackground=>'blue');
    my $b_cls = $fm_kbds->Button(
      -relief=>'raised',-text=>"Finu",-command=>\&quit_MainLoop,
      -background=>"gray",-activebackground=>"red");
    $bn_tajpu->pack(-side=>'left',-expand=>1,-fill=>'x');
    $bn_en->pack(-side=>'left',-expand=>1,-fill=>'x');
    $bn_eo->pack(-side=>'left',-expand=>1,-fill=>'x');
    $b_cls->pack(-side=>'left');
    $fm_kbds->pack(-side=>'top',-expand=>0,-fill=>'x');
    
    ################################
    # BEGIN PROBLEM AREA -- SOLVED #
    ################################
    
    sub tajpu {
        local $SIG{CHLD} = 'IGNORE';   # don't wait for child
                                       # exit status. avoids
                                       # zombies.
        die "fork failed: $!" unless defined($pid_1 = fork);
        return if $pid_1;
    		$feedback = $programo_1;
        exec("$programo_1");
        warn "exec failed: $!";
        CORE::exit(1);
    }
    
    ##############################
    # END PROBLEM AREA -- SOLVED #
    ##############################
    
    sub kbd_eo {
     $feedback = 'Klavaro verdas!';
     `xmodmap $xmodmap_verda`;
    }
    
    sub kbd_en {
     $feedback = 'Klavaro malverdas.';
     `xmodmap $xmodmap_alia`;
    }
    
    # Frame for info.
    my $fm_btm = $mw_kbd->Frame(-relief=>'flat',-borderwidth=>5);
    my $e_feedback = $fm_btm->Entry(
      -width=>20,	
      -textvariable=>\$feedback,-font =>'courier',
      -background=>"white",-foreground=>'blue');
    $e_feedback->pack(-side=>'left',-expand=>1,-fill=>'x');
    $fm_btm->pack(-side=>'bottom',-expand=>0,-fill=>'x');
    
    # Backup results and quit program.
    sub quit_MainLoop {
      $mw_kbd->destroy() if Tk::Exists($mw_kbd);
    }
    
    MainLoop;
    
    And, just for completeness, here is the xternal Esperanto file ~/.Xmodmap_verda which Perl feeds to xmodmap for XFree86. It was created with the /usr/pkgsrc/x11/xkeycaps package.
    !
    ! This is an `xmodmap' input file for 
    !   PC 101 key, thin Delete, tall Enter (XFree86; US) keyboards.
    ! Automatically generated on Thu May 29 01:33:57 2003 by aplonis with
    ! XKeyCaps 2.46; Copyright (c) 1999 Jamie Zawinski <jwz@jwz.org>.
    ! http://www.jwz.org/xkeycaps/
    !
    keycode 0x6F =	Print	Sys_Req
    keycode 0x18 =	ccircumflex	Ccircumflex
    keycode 0x19 =	ubreve	Ubreve
    keycode 0x1D =	jcircumflex	Jcircumflex
    keycode 0x22 =	gcircumflex	Gcircumflex
    keycode 0x23 =	hcircumflex	Hcircumflex
    keycode 0x35 =	scircumflex	Scircumflex
    keycode 0x40 =	Alt_L	Meta_L
    keycode 0x71 =	Alt_R	Meta_R
    
    I will write up a howto for this and post it first on the following URL:

    starling.us/gus_netbsd

    ...then sometime later, translate it for...

    esperanto.us