Python-webkit comes with a simple browser as an example -- on Debian it's installed in /usr/share/doc/python-webkit/examples/browser.py. But it's very minimal, and lacks important basic features like command-line arguments. One of those basic features I've been meaning to add is Back and Forward buttons.
Should be easy, right? Of course webkit has a go_back() method, so I just have to add a button and call that, right? Ha. It turned out to be a lot more difficult than I expected, and although I found a fair number of pages asking about it, I didn't find many working examples. So here's how to do it.
Add a toolbar button
In the WebToolbar class (derived from gtk.Toolbar):
__init__(), after initializing the parent class and
before creating the location text entry (assuming you want your
buttons left of the location bar), create the two buttons:
backButton = gtk.ToolButton(gtk.STOCK_GO_BACK) backButton.connect("clicked", self.back_cb) self.insert(backButton, -1) backButton.show() forwardButton = gtk.ToolButton(gtk.STOCK_GO_FORWARD) forwardButton.connect("clicked", self.forward_cb) self.insert(forwardButton, -1) forwardButton.show()
Now create those callbacks you just referenced:
def back_cb(self, w): self.emit("go-back-requested") def forward_cb(self, w): self.emit("go-forward-requested")
That's right, you can't just call go_back on the web view, because GtkToolbar doesn't know anything about the window containing it. All it can do is pass signals up the chain.
But wait -- it can't even pass signals unless you define them.
__gsignals__ object defined at the beginning
of the class that needs all its signals spelled out.
In this case, what you need is
"go-back-requested": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), "go-forward-requested": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()),Now these signals will bubble up to the window containing the toolbar.
Handle the signals in the containing window
So now you have to handle those signals in the window.
In WebBrowserWindow (derived from gtk.Window), in
after creating the toolbar:
toolbar.connect("go-back-requested", self.go_back_requested_cb, self.content_tabs) toolbar.connect("go-forward-requested", self.go_forward_requested_cb, self.content_tabs)
And then of course you have to define those callbacks:
def go_back_requested_cb (self, widget, content_pane): # Oops! What goes here? def go_forward_requested_cb (self, widget, content_pane): # Oops! What goes here?
But whoops! What do we put there? It turns out that WebBrowserWindow has no better idea than WebToolbar did of where its content is or how to tell it to go back or forward. What it does have is a ContentPane (derived from gtk.Notebook), which is basically just a container with no exposed methods that have anything to do with web browsing.
Get the BrowserView for the current tab
Fortunately we can fix that. In ContentPane, you can get the current page (meaning the current browser tab, in this case); and each page has a child, which turns out to be a BrowserView. So you can add this function to ContentPane to help other classes get the current BrowserView:
def current_view(self): return self.get_nth_page(self.get_current_page()).get_child()
And now, using that, we can define those callbacks in WebBrowserWindow:
def go_back_requested_cb (self, widget, content_pane): content_pane.current_view().go_back() def go_forward_requested_cb (self, widget, content_pane): content_pane.current_view().go_forward()
Whew! That's a lot of steps for something I thought was going to be just adding two buttons and two callbacks.
[ 16:45 Aug 06, 2016 More programming | permalink to this entry | ]