• Embed/Swallow an external X11 prog in Tk

    From kenTk@21:1/5 to All on Tue Jul 31 11:56:53 2018
    I am looking to embed a separate program that is written in c using X11/Xlib etc in to a Tk Frame.
    I started with this rather old posting. https://www.perlmonks.org/?node_id=83360
    which works partially using xterm as the external program.
    Both xterm and my prog suffer the same problem so I will leave it with the xterm example for the sake of this posting.
    The only change that I made to the above script was to change "color_xterm" to "xterm".
    If you call it with a command line argument of 1 it fails to embed.
    With more than 1 it will embed n-1 times. The last iteration fails and you are left with a separate, non-embedded xterm pane.
    It seems that reparent always needs a following call of itself to complete the reparent process. Simply calling it twice each time does not fix it.

    I worked on it for many hours and eventually left it with a band-aid: I made an n+1 iteration using a separate, target Tk parent pane ( which it never reaches)and then killed the n+1 instance of xterm.

    I appreciate that xterm has its own "-into" function for doing this as posted on
    https://www.perlmonks.org/bare/?node_id=359764
    But "-into" is built in. To do something similar I would have to re-write my prog using something like the X Toolkit and XtOpenDisplay instead of XopenDisplay but that is another learning curve.

    Any suggestions would be appreciated.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From kenTk@21:1/5 to kenTk on Fri Aug 10 11:37:39 2018
    On Tuesday, 31 July 2018 19:56:54 UTC+1, kenTk wrote:
    I am looking to embed a separate program that is written in c using X11/Xlib etc in to a Tk Frame.
    I started with this rather old posting. https://www.perlmonks.org/?node_id=83360
    which works partially using xterm as the external program.
    Both xterm and my prog suffer the same problem so I will leave it with the xterm example for the sake of this posting.
    The only change that I made to the above script was to change "color_xterm" to "xterm".
    If you call it with a command line argument of 1 it fails to embed.
    With more than 1 it will embed n-1 times. The last iteration fails and you are left with a separate, non-embedded xterm pane.
    It seems that reparent always needs a following call of itself to complete the reparent process. Simply calling it twice each time does not fix it.

    I worked on it for many hours and eventually left it with a band-aid: I made an n+1 iteration using a separate, target Tk parent pane ( which it never reaches)and then killed the n+1 instance of xterm.

    I appreciate that xterm has its own "-into" function for doing this as posted on
    https://www.perlmonks.org/bare/?node_id=359764
    But "-into" is built in. To do something similar I would have to re-write my prog using something like the X Toolkit and XtOpenDisplay instead of XopenDisplay but that is another learning curve.

    Any suggestions would be appreciated.


    An update after more investigations and tests:
    I have created this, smallest possible X program that, when called from perl enables ReparentWindow to work.
    // smallX.c
    #include <X11/Xlib.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    Display *theDisplay;
    int main(int argc, char ** argv)
    {
    // Connect to the display server
    theDisplay = XOpenDisplay(NULL);
    if (!theDisplay) {fprintf(stderr, "unable to connect to display\n");return 7;}
    XCloseDisplay(NULL); // Only for tidyness
    return 0;
    }

    The simplified and modified Tk that I am using for the test:
    #!/usr/bin/perl
    # $Id: ptk_steal.pl,v 1.1 1999/07/01 19:56:31 eserte Exp $
    # Author: Slaven Rezic
    # Copyright (C) 1999 Slaven Rezic. All rights reserved.
    # This program is free software; you can redistribute it and/or
    # modify it under the same terms as Perl itself.
    # Mail:
    # WWW: http://user.cs.tu-berlin.de/~eserte/
    # Modified by KVS Aug 2018

    use strict;
    use Tk;
    use X11::Protocol;

    my $x = X11::Protocol->new();
    my $top = MainWindow->new(-width=>850,-height=>525);
    my $pid;
    my $wid;

    $top->Label( -text => "A xterm:" )->place(-x=>200,-y=>1);
    $top->Button(-text => 'Exit',
    -command => sub{
    kill(9,$pid);
    $top->destroy})->place(-x=>4,-y=>5);

    my $f = $top->Frame( -width => 600, -height => 500,'-container' => 1,-background=>'blue' )->place(-x=>200,-y=>20);
    update;

    unless($pid = fork)
    {
    exec("/usr/bin/xterm -name WindowToSteal");
    }


    my $check = $top->repeat(50,sub { $wid = get_window_by_name("WindowToSteal");});

    while ( !defined $wid )
    {
    $top->waitVariable( \$wid );
    }
    $check->cancel;

    ReparentWindow( $wid, oct( $f->id ), 100, 100 );

    # THE FOLLOWING LINE MAKES ReparentWindow WORK. WITHOUT IT xterm WONT GO IN THE # FRAME.
    system("./smallX");

    MainLoop();

    sub get_window_by_name
    {
    _get_window_by_name( $x->{'root'}, $_[0] );
    }

    sub _get_window_by_name
    {
    my ( $root, $searchname ) = @_;
    my ( $dummy, $dummy2, @new_kids ) = $x->QueryTree($root);
    foreach my $k (@new_kids) {
    my $atomnr;

    foreach my $atom ( $x->ListProperties($k) )
    {
    if ( $x->GetAtomName($atom) eq "WM_CLASS" )
    {
    $atomnr = $atom;
    last;
    }
    }
    if ( defined $atomnr )
    {
    my ($classprop) =
    $x->GetProperty( $k, $atomnr, "AnyPropertyType", 0, 256, 0);

    my ( $class, $name ) = split( /\0/, $classprop );
    if ( $class eq $searchname )
    {
    return $k;
    }
    }
    my $ret = _get_window_by_name( $k, $searchname );
    if ( defined $ret )
    {
    return $ret;
    }
    }
    undef;
    }

    __END__

    It looks like there is a pipeline which needs to be flushed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)