I'm very new to Python and have no object-oriented background. What's worse, is that I want to be able to Do Stuff(), so I'm working through a number of online resources, including the very helpful 'Learn Python the Hard Way,' to try and get the concepts and practice. I could really use some guidance in a project that's beyond my skills at the moment.
I'm trying to build a program that launches a browser session using WebKitGTK and also runs a small listening daemon. I'd like to send signals to the server, which relays commands to the WebKit instance via Telnet... for now, a page refresh would be enough. I needed this to be nonblocking, so, through tons of reading and fouls, this is what I have:
main.py: - starts the listening server using the multiprocessing module - launches the browser display
server.py: - runs the server that listens on a port for Telnet connections. The 'while' loop is where I'd like to process the commands received.
display.py: - creates and runs the Webkit instance
My question:
How do I reference the WebKit instance within 'server.py?' I tried creating a global module that defines the GTK/WebKit object, and is then accessed in 'server.listener,' but I'm lost in how to send signals to this.
I know this isn't neat or efficient, but my code follows. Thanks for pointing me in the right direction.
############################
# main.py
############################
import multiprocessing
import server
import display
if __name__ == '__main__':
    serv = multiprocessing.Process(name='serverproc', target=server.listener)
    serv.start()
    display.browser()
############################
# server.py
############################
import socket
import sys
import gtk
def listener():
    HOST = ''
    PORT = 8089
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    try:
        sock.bind((HOST, PORT))
    except socket.error as msg:
        print 'Failed to bind. Error: ' + str(msg[0]) + ' Message ' + msg[1]
        sys.exit()
    print 'Socket bound'
    sock.listen(10)
    print 'Socket listening'
    while True:
        conn, address = sock.accept()
        print 'Connected with ' + address[0] + ':' + str(address[1])
        data = conn.recv(64).strip()
        print 'Received: ' + data + '\n'
        if not data:
            break
        '''
        This is where I'd like to be able to send a page refresh signal to the
        Webkit instance:
        '''
        if data == 'restart':
            print 'Attempting to restart'
            break
        conn.close()
    conn.close()
    sock.close()
############################
# display.py
############################
import gtk
import webkit
import gtk.gdk as GDK
def browser():
    width = 500
    height = 800
    w = gtk.Window()
    w.connect("destroy", gtk.main_quit)
    w.set_title("Browser")
    w.resize(width,height)
    w.set_keep_above(True)
    w.set_decorated(False)
    client = webkit.WebView()
    client.open('http://127.0.0.1/index.php')
    client.set_editable(False)
    client.set_size_request(width, height)
    w.add(client)
    w.show_all()
    gtk.main()
UPDATE:
Okay, I put everything in a single module and created a class, "Display," which has 'init' and 'server' methods. When I pass 'hello' to the server, it prints a Display object address ("Display object at 0x7f20e18a7c80 [GtkWindow at 0x23850e0]"), but I don't understand why the URL doesn't actually change in the webkit instance. Could someone help? Here's my updated code:
############################
# display.py
############################
import os
import gtk, gobject
import webkit
import socket
import multiprocessing
# ================================================= #
class Display(gtk.Window):
    def __init__(self):
        w = 600
        h = 800
        gtk.Window.__init__(self)
        self.set_default_size(w, h)
        self.browser = webkit.WebView()
        self.browser.set_size_request(w, h)
        self.add(self.browser)
        self.connect('destroy', gtk.main_quit)
        self.browser.open('http://127.0.0.1/index.php')
        self.show_all()
    def server(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.bind(('127.0.0.1', 8089))
        sock.listen(5)
        while True:
            conn, address = sock.accept()
            data = conn.recv(64).strip()
            if data == 'hello':
                print self
                self.browser.open('http://127.0.0.1/newpage.php')
            conn.close()
        conn.close()
        sock.close()
# ================================================= #
if __name__ == "__main__":
    b = Display()
    serv = multiprocessing.Process(name='serverproc', target=b.server)
    serv.start()
    gtk.main()
SOLUTION:
For the sake of completion, here's the full solution (yes, I'm on Python 2.7.9).
############################
# display.py
############################
import os
import gtk, gobject
import webkit
import socket
import glib
import threading
# ================================================= #
class Display(gtk.Window):
    def __init__(self):
        w = 600
        h = 800
        gtk.Window.__init__(self)
        self.set_default_size(w, h)
        self.browser = webkit.WebView()
        self.browser.set_size_request(w, h)
        self.add(self.browser)
        self.connect('destroy', gtk.main_quit)
        self.browser.open('http://127.0.0.1/index.php')
        self.show_all()
    def server(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.bind(('127.0.0.1', 8089))
        sock.listen(5)
        while True:
            conn, address = sock.accept()
            data = conn.recv(64).strip()
            if data == 'hello':
                print self
                glib.idle_add(self.browser.open, 'http://127.0.0.1/newpage.php')
            conn.close()
        conn.close()
        sock.close()
# ================================================= #
if __name__ == "__main__":
    b = Display()
    serv = threading.Thread(name='serverproc', target=b.server)
    serv.start()
    gtk.main()
				
                        
You can use a class for modelling the window (classes are very useful in general for implementing GUIs) and run the server in a thread. Therefore, you can use python's
threading.Thread. You still have to pay attention when you modify the Gtk widgets from a thread. Gtk comes with its own mechanism for it. You can simply useGLib.idle_add()and you won't run into problems caused by concurrent modification.(The working result is visible in the edited question.)