[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: Idea: Can we modify Devel::REPL or combine with Perl Object Environment to have programmatic interaction with a gtk2-perl process like in other languages?





--- On Sun, 4/19/09, Mitchell Laks <mlaks post harvard edu> wrote:

> From: Mitchell Laks <mlaks post harvard edu>
> Subject: Idea: Can we modify Devel::REPL or combine with  Perl Object Environment to have programmatic interaction with a gtk2-perl process like in other languages?
> To: gtk-perl-list gnome org
> Date: Sunday, April 19, 2009, 8:25 PM
> 
> Hi,
> 
> I like perl and gtk2  and   would
> rather use it than  xyz (other languages :)). 
> 
> Can we set up a working interactive REPL with gtk2-perl as
> with pygtk for instance. I can use Devel::REPL to start
> and  build the gui
> but then I lose the interaction control once I start
> Gtk2->main;
> 
> I would like to redefine callbacks, change widgets on the
> fly etc as we continue the interaction using Devel::REPL. I
> have done it with pygtk of course using the program
> pygtkconsole.py. Do we modify Devel::REPL or set up
> something with perl POE?
> 
> 
> I think we should be able to do this with gtk2-perl,
> although I am still learnining some of this stuff so I
> wanted your opinions on the details. Could we use perl POE?
> 
> 
> Hw to keep access to the working program? Now I know that
> there are issues with gui threads. However can you imagine
> doing something with perl POE?
> 
> Thanks
> 
> Mitchell
> 
> Here for instance is what they do in pygtk:
> 
> In the pygtk tutorial: 
> 
> http://www.pygtk.org/pygtk2tutorial/ch-Introduction.html#sec-ExploringPygtk
> 
> you can set up a pygtk window and dynamically from the
> interactive shell drop child widgets
> and add new ones to replace them and then change callbacks
> etc.
> 
> here is pygtkconsole.py
> 
> #!/usr/bin/env python
> # -*- Mode: python; c-basic-offset: 4 -*-
> #
> # Interactive PyGtk Console, Johan Dahlin 2002
> #
> 
> import os
> import signal
> import sys
> import string
> import socket, select
> from code import InteractiveInterpreter,
> InteractiveConsole
> 
> import gtk
> import gobject
> 
> # For compatibility, instead of using GDK.INPUT_READ or
> # gtk.gdk.INPUT_READ depending on the PyGtk version
> GDK_INPUT_READ = 1
> 
> class Mainloop(InteractiveInterpreter):
>     def __init__(self, read_fd, sock):
>        
> InteractiveInterpreter.__init__(self)
>         self._rfd = os.fdopen(read_fd,
> 'r')
>         self._sock = sock
>         gobject.io_add_watch(read_fd,
> GDK_INPUT_READ, self.input_func)
> 
>     def read_message(self):
>         length =
> ord(self._rfd.read(1))
>         return self._rfd.read(length)
> 
>     def input_func(self, fd, cond):
>         data = self.read_message()
>         more = self.runsource(data)
>         self._sock.send(chr(more))
>         return True
> 
>     def run(self):
>         gtk.main()
>         
> class Console(InteractiveConsole):
>     def __init__(self, write_fd, sock, pid):
>        
> InteractiveConsole.__init__(self)
>         self._wfd = os.fdopen(write_fd,
> 'w')
>         self._sock = sock
>         self.pid = pid
> 
>     def send_message(self, message):
>         self._wfd.write('%c%s' %
> (len(message), message))
>         self._wfd.flush()
> 
>     def interact(self, banner=None):
>        
> InteractiveConsole.interact(self, banner)
>         # Die child die
>         os.kill(self.pid, 9)
>         
>     def runsource(self, source, filename):
>         self.send_message(source)
>         # wait for notification from
> parent
>        
> select.select([self._sock],[],[])
>         more = ord(self._sock.recv(1))
>         return more
>         
> class GtkInterpreter(Console):
>     def __init__(self):
>         rfd, wfd = os.pipe()
>         # set up socket for returning
> command result
>         sigsock =
> socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>         sock_addr = None
>         for port in range(4321,5321):
>             try:
>                
> sigsock.bind(('', port))
>                
> sock_addr = ('', port)
>             except:
>                
> pass
>         if not sock_addr:
>             print "Can't open
> socket"
>         sigsock.listen(1)
> 
>         parent_pid = os.getpid()
>         child_pid = os.fork()
>         if not child_pid:
>             # connect to
> command return socket
>             sock =
> socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>            
> sock.connect(sock_addr)
>             g = Mainloop(rfd,
> sock)
>             g.run()
>         else:
>             # Wait for
> command return socket connection
>             sock, addr =
> sigsock.accept()
>            
> Console.__init__(self, wfd, sock, child_pid)
> 
> def interact():
>     try:
>         import readline
>         import rlcompleter
>         readline.parse_and_bind('tab:
> complete')
>     except ImportError:
>         pass
>     
>     gi = GtkInterpreter()
>     gi.push("from gtk import *")
> 
>     python_version =
> string.split(sys.version)[0]
>     try:
>     pygtk_version = string.join(map(str,
> gtk.pygtk_version), '.')
>     gtk_version = string.join(map(str,
> gtk.gtk_version), '.')
>     except:
>     pygtk_version = '0.6.x'
>     gtk_version = '1.2.x'
> 
>     banner = """Python %s, PyGTK %s (Gtk+ %s)
> Interactive console to manipulate GTK+ widgets.""" %
> (python_version,
>        pygtk_version,
>        gtk_version)
>     gi.interact(banner)
>     
> if __name__ == '__main__':
>     interact()
> 
> 
> 
> 
> 
> 
> 
> 
> I would like to be able to interact programmatically with a
> working gtk2-perl program through a REPL, as one might in
> lisp or in python. Thus redefine callbacks etc.
> change baby widgets whatever one wanted to do. It seems
> like a cool thing to be able to do. I read a story somewhere
> about progammers who attached to a live 
> lisp process to debug a satellite in orbit, and this would
> be nice for us to do with perl too.
> 
> 

Well, I do not know Python except for vewry basic/primitive stuff.

However, Perl is a "strategically" different from Python language, i.e. it
has fundamental features Python doesn't have or has them in a very
rudimentary form.

The features are:

* closures;
* lexical scoping;
* anonimyty.

I.e. its functional features.

So, to add something to a running Perl program is different from the same
in Python.

For example, the following (AFAIK) cannot be translated into Python without
adding extra names:

  { 
  my $parent = $this; 
 
  my $on_text  = "On"; 
  my $off_text = "Off"; 
 
  my $this = Gtk2::ToggleButton->new($off_text); 
 
  $this->signal_connect 
    ( 
    clicked => 
      sub 
        { 
        if($this->get_active) 
          { 
          $this->set_label($on_text); 
          } 
        else 
          { 
          $this->set_label($off_text); 
          } 
 
        # do the real stuff here 
        } # sub 
    ); # $this->signal_connect 
 
  $parent->pack_start($this, FALSE, FALSE, 0); 
 
  $this->show; 
  }
.

Note there is a number of hierarchy levels, and each of them has its own
$this, $parent.

Using lexical scoping you can easily add as many nested levels as you
wish, still just using

  {
  my $parent = $this; # this $this belongs to outer scope
  ...
  my $this = SomeClass->new(...); # this $this belongs to this scope and
                                  # defines a new widget/instance/etc.
  ...
  }

I.e. in Perl it's very easy to add things from inside, and lexical scoping
provided excellent encapsulation/data protection, so it's impossible by
normal means to access inner data from outside.

Adding code from inside is simple - either you just write it, or you
do it this way:

  {
  ... # existing stuff
  do "file_with_new_stuff.pl"; # code in the file is evaluated in the
                               # current scope, so all lexical variable are
                               # accessible
  ... # existing stuff
  }

For example, 'glade' (AFAIR) just creates stuff at top level (variables)
making the code unmaintainable.

One, of course, can downgrade Perl to Python, but I wouldn't be interested
in such a code.

I used 'glade' to obtain an idea how the GUI will look, but then I
implemented it from scratch taking from 'glade' widgets hierarchies.

To put it short - if you invent a method on the fly to add moral
equivalents of

 do "file_with_new_stuff.pl"

above on the fly - it's a start.


Regards,
  Sergei.






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]