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?
- From: Sergei Steshenko <sergstesh yahoo com>
- To: gtk-perl-list gnome org, Mitchell Laks <mlaks post harvard edu>
- Subject: 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?
- Date: Sun, 19 Apr 2009 22:09:46 -0700 (PDT)
--- 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]