wxWebkit on Intrepid

wxWebKit is a very important cross-platform control for the wxPython GUI toolkit. It enables you to display complex HTML pages (including live from the web) e.g. tabular output or help files.

Fortunately, wxWebkit can be made to work on Ubuntu Intrepid. Indeed, I am editing this blog item right now from within a wxPython wxWebKit control :-). But it is not a straight forward process at this time and it is not properly installed as such. But you can start testing it after following the steps suggested below.

[Update – there is now a deb file you can use thanks to Christoph Willing. Use the following commands:
# NB the next line is one long command line
sudo wget http://www.vislab.uq.edu.au/debuntu/sources.list.d/intrepid.list -O /etc/apt/sources.list.d/uqvislab.list

sudo apt-get update

sudo apt-get install python-webkitwx
]

I was never able to get wxWebKit to compile and work following the instructions here http://wxwebkit.wxcommunity.com/index.php?n=Main.Requirements. I expect this will change in the future.

Here are some instructions that have worked for me on more than one machine. My deepest thanks go to Christoph Willing and Kevin Ollivier.

Get the correct wx swig deb from http://www.vislab.uq.edu.au/debuntu/intrepid/swigwx1.3_1.3.29_i386.deb and install it.

Get a patched bakefile deb from http://www.vislab.uq.edu.au/debuntu/intrepid/bakefile_0.2.5-1_i386.deb and install it.

Get intrepid_prereqs and i_files.tar.gz from http://www.vislab.uq.edu.au/research/accessgrid/software/debuntu/wxwebkit/.

Run the prereqs file from the folder you have stored it in e.g. Desktop:

cd ~/Desktop
sudo bash intrepid_prereqs

Then extract the i_files folder from i_files.tar.gz and put it (the folder with its contents, not just the contents) under: /usr/include/wx-2.8/wx/wxPython

OK – the preparation is done. Now to get the source by checking out the subversion repository:

cd ~
svn checkout http://svn.webkit.org/repository/webkit/trunk WebKit

Then cd into ~/WebKit/WebKitTools/Scripts and run:
./build-webkit --wx --wx-args="wxgc wxpython" 2>&1 | tee op

NB if your build fails for some reason and you want to run it again, run clean first:
./build-webkit --wx --wx-args="wxgc wxpython" --clean

The file op will be made in ~/WebKit/WebKitTools/Scripts so you can check what happened. If your build is successful there will be a clear message to that effect at the end. Regrettably, an absence of error messages is not the presence of success ;-).

To test wxWebKit you will need to save the following file in the ~/WebKit/WebKitBuild/Release folder (this is a minor variation of the standard test file to sidestep some bugs).

#!/usr/bin/python

# Copyright (C) 2007 Kevin Ollivier All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import wx
import webview

class TestPanel(wx.Panel):
def __init__(self, parent, log, frame=None):
wx.Panel.__init__(self, parent, -1,
style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN|wx.NO_FULL_REPAINT_ON_RESIZE)
self.log = log
self.current = "http://wxPython.org/"
self.frame = frame

if frame:
self.titleBase = frame.GetTitle()

sizer = wx.BoxSizer(wx.VERTICAL)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)

self.webview = webview.WebView(self, -1)

btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)

btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)

btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)

btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT)
self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn)
btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2)

txt = wx.StaticText(self, -1, "Location:")
btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2)

self.location = wx.ComboBox(self, -1, "",
style=wx.CB_DROPDOWN|wx.PROCESS_ENTER)

self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location)
self.location.Bind(wx.EVT_KEY_UP, self.OnLocationKey)
self.location.Bind(wx.EVT_CHAR, self.IgnoreReturn)
btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2)

sizer.Add(btnSizer, 0, wx.EXPAND)
sizer.Add(self.webview, 1, wx.EXPAND)

self.webview.LoadURL(self.current)
self.location.Append(self.current)

# self.webview.Bind(webview.EVT_WEBVIEW_STATE_CHANGED, self.OnStateChanged)

self.SetSizer(sizer)

def OnStateChanged(self, event):
statusbar = self.GetParent().GetStatusBar()
if statusbar:
if event.GetState() == webview.WEBVIEW_STATE_NEGOTIATING:
statusbar.SetStatusText("Contacting " + event.GetURL())
elif event.GetState() == webview.WEBVIEW_STATE_TRANSFERRING:
statusbar.SetStatusText("Loading " + event.GetURL())
elif event.GetState() == webview.WEBVIEW_STATE_STOP:
statusbar.SetStatusText("")
self.location.SetValue(event.GetURL())
self.GetParent().SetTitle("wxWebView - " + self.webview.GetPageTitle())

def OnLocationKey(self, evt):
if evt.GetKeyCode() == wx.WXK_RETURN:
URL = self.location.GetValue()
self.location.Append(URL)
self.webview.LoadURL(URL)
else:
evt.Skip()

def IgnoreReturn(self, evt):
if evt.GetKeyCode() != wx.WXK_RETURN:
evt.Skip()

def OnLocationSelect(self, evt):
url = self.location.GetStringSelection()
self.webview.LoadURL(url)

def OnOpenButton(self, event):
dlg = wx.TextEntryDialog(self, "Open Location",
"Enter a full URL or local path",
self.current, wx.OK|wx.CANCEL)
dlg.CentreOnParent()

if dlg.ShowModal() == wx.ID_OK:
self.current = dlg.GetValue()
self.webview.LoadURL(self.current)

dlg.Destroy()

def OnPrevPageButton(self, event):
self.webview.GoBack()

def OnNextPageButton(self, event):
self.webview.GoForward()

def OnStopButton(self, evt):
self.webview.Stop()

def OnRefreshPageButton(self, evt):
self.webview.Reload()

class wkFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "WebKit in wxPython!")

self.panel = TestPanel(self, -1)
# self.panel.webview.LoadURL("http://www.wxwidgets.org/")
self.CreateStatusBar()

class wkApp(wx.App):
def OnInit(self):
self.webFrame = wkFrame()
self.SetTopWindow(self.webFrame)
self.webFrame.Show()

return True

app = wkApp(redirect=False)
app.MainLoop()

Assuming you named that file my_wxwebkit_test.py, cd into ~/WebKit/WebKitBuild/Release and run

export LD_LIBRARY_PATH=`pwd`

so that the library files can be found in spite of their unexpected location (because we haven’t properly installed our files into the standard locations). Then run

python my_wxwebkit_test.py

and enjoy :-).