class SessionTab(gobject.GObject): PROCNAME = "browser.py" __gsignals__ = { "close": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "status":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "title":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "location":(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) } def __init__(self, url, title="new"): super(SessionTab, self).__init__() self.socket = gtk.Socket() self.socket.connect("plug-removed", self.close) self.label = TabLabel(title) self.label.connect("close", self.close) self.proc = None self.source_id = None self.status = "" self.title = "" self.location = url self.wid = -1 self.close_emitted = False @property def child(self): return self.socket def show(self): self.socket.show() self.label.show_all() self.wid = self.socket.get_id() show_all = show def destroy(self): if self.source_id is not None: gobject.source_remove(self.source_id) self.proc.kill() self.socket.destroy() self.label.destroy() def add_to_notebook(self, notebook): notebook.append_page(self.socket, self.label) notebook.set_tab_reorderable(self.socket, True) notebook.set_tab_detachable(self.socket, True) return notebook.page_num(self.socket) def start(self, url, title): basedir = os.path.dirname(__file__) sessionproc = os.path.join(basedir, self.PROCNAME) cmd = [sys.executable, sessionproc, str(self.wid), url, title] self.proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) ## force non-blocking ## import fcntl ## fl = fcntl.fcntl(self.proc.stdout, fcntl.F_GETFL) ## fcntl.fcntl(self.proc.stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK) self.source_id = gobject.io_add_watch(self.proc.stdout, gobject.IO_IN, self.handle_child) gobject.io_add_watch(self.proc.stdout, gobject.IO_HUP|gobject.IO_ERR, self.handle_child_closed) gobject.io_add_watch(self.proc.stdin, gobject.IO_HUP|gobject.IO_ERR, self.handle_child_closed) def close(self, *args): if not self.close_emitted: self.close_emitted = True self.emit("close") def send(self, cmd): self.proc.stdin.write("%s\n%s" % (len(cmd), cmd)) self.proc.stdin.flush() def handle_child_closed(self, source, condition): print "Error on", self, "closing..." self.close() return False def handle_child(self, source, condition): """ the child wrote something to stdout """ #print "handle_child", source, condition data = source.readline() if not data: print "No data from", self, "closing..." self.close() return False try: s = int(data) except ValueError, e: #print "Noise" return True data = source.read(s) if " " in data: cmd, rest = data.split(" ", 1) else: cmd, rest = data, "" if cmd == "status": self.status = rest self.emit("status") elif cmd == "title": self.title = rest self.emit("title") elif cmd == "location": self.location = rest self.emit("location") print "CHILD wrote", data return True
class SessionTab(gobject.GObject): PROCNAME = "browser.py" __gsignals__ = { "close": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "status": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "title": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "location": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) } def __init__(self, url, title="new"): super(SessionTab, self).__init__() self.socket = gtk.Socket() self.socket.connect("plug-removed", self.close) self.label = TabLabel(title) self.label.connect("close", self.close) self.proc = None self.source_id = None self.status = "" self.title = "" self.location = url self.wid = -1 self.close_emitted = False @property def child(self): return self.socket def show(self): self.socket.show() self.label.show_all() self.wid = self.socket.get_id() show_all = show def destroy(self): if self.source_id is not None: gobject.source_remove(self.source_id) self.proc.kill() self.socket.destroy() self.label.destroy() def add_to_notebook(self, notebook): notebook.append_page(self.socket, self.label) notebook.set_tab_reorderable(self.socket, True) notebook.set_tab_detachable(self.socket, True) return notebook.page_num(self.socket) def start(self, url, title): basedir = os.path.dirname(__file__) sessionproc = os.path.join(basedir, self.PROCNAME) cmd = [sys.executable, sessionproc, str(self.wid), url, title] self.proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) ## force non-blocking ## import fcntl ## fl = fcntl.fcntl(self.proc.stdout, fcntl.F_GETFL) ## fcntl.fcntl(self.proc.stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK) self.source_id = gobject.io_add_watch(self.proc.stdout, gobject.IO_IN, self.handle_child) gobject.io_add_watch(self.proc.stdout, gobject.IO_HUP | gobject.IO_ERR, self.handle_child_closed) gobject.io_add_watch(self.proc.stdin, gobject.IO_HUP | gobject.IO_ERR, self.handle_child_closed) def close(self, *args): if not self.close_emitted: self.close_emitted = True self.emit("close") def send(self, cmd): self.proc.stdin.write("%s\n%s" % (len(cmd), cmd)) self.proc.stdin.flush() def handle_child_closed(self, source, condition): print "Error on", self, "closing..." self.close() return False def handle_child(self, source, condition): """ the child wrote something to stdout """ #print "handle_child", source, condition data = source.readline() if not data: print "No data from", self, "closing..." self.close() return False try: s = int(data) except ValueError, e: #print "Noise" return True data = source.read(s) if " " in data: cmd, rest = data.split(" ", 1) else: cmd, rest = data, "" if cmd == "status": self.status = rest self.emit("status") elif cmd == "title": self.title = rest self.emit("title") elif cmd == "location": self.location = rest self.emit("location") print "CHILD wrote", data return True
class NotebookPage(gobject.GObject): __gsignals__ = { "close": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "status": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "title": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "url": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "debug": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) } def __init__(self, url, title="new"): super(NotebookPage, self).__init__() self.hover = None self.throbbing = False self.label = TabLabel(title) self.label.connect("close", self.close) self.browser = Browser(enable_inspector=True) self.browser.connect("notify::load-status", self.load_status) self.browser.connect("hovering-over-link", self.hovering_over_link) self.browser.connect("title-changed", self.handle_title_changed) self.browser.connect("icon-loaded", self.handle_icon_loaded) self.browser.connect("download-requested", self.handle_download_requested) self.browser.connect_after("populate-popup", self.populate_popup) self.open(url) self.win = gtk.ScrolledWindow() self.win.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC self.win.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC self.win.add(self.browser) self.win.show_all() self.status = "" self.title = "" self.hover = None self.debug = "" @property def child(self): return self.win @property def current_url(self): return self.browser.get_main_frame().get_uri() or "" @property def current_title(self): return self.browser.get_main_frame().get_title() or self.current_url def add_to_notebook(self, notebook): page = notebook.append_page(self.win, self.label) notebook.set_tab_reorderable(self.win, True) notebook.set_tab_detachable(self.win, True) return page def close(self, widget): self.emit("close") def show(self): self.win.show_all() self.label.show_all() def destroy(self): self.win.destroy() self.label.destroy() show_all = show def grab_focus(self): self.browser.grab_focus() def show_throbber(self): self.throbbing = True throbber = os.path.join(os.path.dirname(__file__), "throbber.gif") self.label.icon.set_from_file(throbber) def open(self, url): if url == "about:blank": self.browser.load_string(ABOUT_PAGE, "text/html", "utf-8", "about") else: self.browser.open(url) self.show_throbber() def back(self): self.browser.go_back() def forward(self): self.browser.go_forward() def reload(self): self.show_throbber() self.browser.reload() ## handlers def load_status(self, widget, *a, **b): status = self.browser.get_load_status() if status == webkit.LOAD_COMMITTED: self.show_throbber() self.emit("url") if status == webkit.LOAD_FINISHED: self.title = self.current_title self.label.text = self.title self.emit("title") if self.throbbing: self.throbbing = False self.label.icon.set_from_stock(gtk.STOCK_ORIENTATION_PORTRAIT, gtk.ICON_SIZE_MENU) ## handle_icon_loaded may follow, setting the actual favicon ## widget.execute_script("alert('Hello')") #if self.browser.get_load_status() == webkit.LOAD_COMMITTED: # self.debug = "ok" #else: # self.debug = "%s %s %s" % (self.browser.get_load_status(), a, b) #self.emit("debug") def hovering_over_link(self, view, title, uri): self.status = uri or "" self.hover = uri self.emit("status") def handle_title_changed(self, view, frame, title): self.title = title self.emit("title") def handle_icon_loaded(self, view, uri, *a): ## This may block, which is bad! pixbuf = favcache.get(uri) self.label.icon.set_from_pixbuf(pixbuf) self.throbbing = False def handle_download_requested(self, widget, download, *a, **b): ## popup, etc XXX name = download.get_uri().rsplit('/')[-1] download.set_destination_uri("file:///tmp/" + name ) return True def populate_popup(self, view, menu): open_in_browser = gtk.MenuItem("Open in default browser") open_in_browser.connect('activate', self.open_in_browser) menu.append(open_in_browser) menu.show_all() return False def open_in_browser(self, menu_item): if self.hover: webbrowser.open(self.hover)