PyGUI as a standard GUI API for Python?

lkcl luke.leighton at googlemail.com
Sat Oct 11 05:19:24 EDT 2008


On Sep 3, 4:34 pm, Michael Palmer <m_palme... at yahoo.ca> wrote:

> So far, development of PyGUI seems to be a one-man effort, and it may
> be slowed down by the attempt to develop the API and the
> implementations concurrently. Could it be useful to uncouple the two,
> such that the API would be specified ahead of the implementation?


michael, i went back to the beginning of this thread, to reply to your
question, because i have some insights to share with you from my
failed attempts on porting pyjamas to the desktop - which you can
collect here: http://lkcl.net/pyjamas-desktop

there, you will find an IronPython-GtkSharp port; a pyqt4 port and a
pygtk2 port.  they were each failures in their own unique and special
ways.

to explain: pyjamas is a widget set api that looks desktop-like; you
write code in python, it's compiled to javascript; the DOM.py module
actually does things like document.getElementById() etc. etc. and in
this way you end up completely manipulating the DOM model, turning the
browser into just a giant desktop-like canvas.

in fact, the pyjamas widget set api is _so_ similar to a desktop api
that i decided to have a go at porting it _to_ the desktop.
eventually i succeeded.

the first attempt was with ironpython.  i actually got a long way with
this one - i chewed through the pyjamas examples in about a day.  i
had a small stumbling block implementing the HTML() widget, but
GtkSharp.HTML came to the rescue, there, and i was off again.
i then ran into a wall i decided not to bash my head against at such
an early stage (36 hours) - an implementation of XMLHTTPRequest
(remember - i was implementing every single bit of functionality that
a DOM model has access to).

so, i decided to port the ironpython port to pygtk2.  unfortunately,
whilst i got a lot further and managed to implement all of the
examples, there was no equivalent of HTML().  GTK itself totally lacks
a rich media content widget.  there is python-gtkhtml2 which is good,
but not good enough.  the much better gtkhtml3 library doesn't have
python bindings around it, and i wasn't in the mood to write any (and
hadn't at the time any experience with pygtk codegen.py).

also i heard that gtkhtml2 had been abandoned, and gtkhtml3 wasn't
going to be followed up on, and that there were rumours about webkit.

crucially - much more importantly - gtkhtml 2 and 3 have absolutely no
"automatic" resizing of the HTML content within them.  so, unless you
specify both the width and the height of the widget container, you end
up with a flatlined widget.  by that i mean a widget of say 200 pixels
in width but ZERO pixels in height!  and, as you may well know, if you
specify a width and height on a gtk widget, that's it: it's entirely
fixed.  there's no going back.  you're screwed.

this was an absolute killer.

with no foresight in the design of gtk or gtkhtml2 to make even a
_guess_ at the width and height of the content, the port was screwed.
i made half-hearted attempts to not specify width/height at all, but
all that that resulted in was piss-poor layout, and when you shrank
the app to small size, all the text disappeared because there was a
margin defaulting to 5px or so and all but the top left corner of the
text boxes would disappear!

so, there was no point in me attempting to make python bindings around
gtkhtml3, even though it has a system for inserting widgets into HTML
(using span ids).

and, even though there's python-gtkmozembed wrappers which would have
allowed me to embed flash plugins etc. into my application, thus
neatly emulating the way that html allows you to do that.

so - sadly - on to pyqt4.

well, i say sadly, but it was actually quite fun.  i'm doing a
complete comprehensive test of absolutely every single feature of the
major widget sets out there, crawling every single corner of their
functionality in order to map concepts one-for-one, and finding that
they don't really cope.

pyqt4.  again, i got a long long way.  the rich media support of qt4
allowed me to do widgets that looked reasonable.  i even had, by that
time, a non-asynchronous version of XMLHTTPRequest.  then i got to the
implementation of Grid() and FlexTable().  this is where it started to
go wrong.

pyqt4 has the concept of layouts.  a layout can be a horizontal
layout, vertical, grid, and you can even specify the percentage or
ratio of the width (or height) that individual cells can use. you
attach a layout to a widget; you can attach layouts to layouts.  you
can remove layouts from widgets.  what you _can't_ do is _remove_
layouts from layouts.

disappointingly, this was the killer, for me.  it was just getting...
too complicated.  i had already encountered advice that, in order to
implement the means to move widgets around, i should remove
*everything* and redo the layout.  it just... wasn't happening.

plus, i  think also that there are problems, again, with the HTML
layout: you can't _entirely_ stop text-squashing.  so, although pyqt4
was _better_, it still wasn't _enough_.

so, i was _almost_ ready to give up, entirely, when i'd heard about
webkit - http://webkit.org - and this looked _perfect_.  the only down-
side: it didn't have python bindings.  a quick search showed
pywebkitgtk.

so, i decided to try something absolutely awful: wrap the
_javascript_!  i augmented pywebkitgtk, thanks to some assistance from
the author of midori i borrowed some of his code and made it possible
for pywebkitgtk to execute javascript code-fragments (equivalent of
eval and exec).  except, immediately i ran into a problem: how to pass
in function call arguments.  i decided against doing func_code
grunginess and creation of variable scope management to emulate python
local function call context (!!!) and instead... insanely...

... dived straight into adding glib bindings around webkit, with a
view to then doing python-bindings around the glib bindings, using
pygtk2's "codegen.py". ... cue piped elevator music and such-like, to
substitute for two weeks of intensive programming, involving python, c+
+, perl, c ...  suffice to say: it worked.  it actually bloody worked.

very very quickly, i was able, once i had the glib bindings, to port
pyjamas to webkit.  i had my first succesful hello world within under
an hour; i had most of the examples done within 18 hours or
thereabouts; the entire port was completed within about five days,
because i had to go back and add extra functionality such as event
handling and XMLHTTPRequest.

when i say "done" i mean that you can do eeevvverrryything that
everyone keeps lamenting about that pygtk2 and pyqt4 lack.  complete
and full support for CSS stylesheets.  complete and full support for
embedded plugins (such as adobe).  complete and full support for HTML
syntax.  _proper_ HTML, not a subset.  you even get the added bonus of
being able to execute javascript fragments, if you're feeling
particularly obtuse.

and, with a few days extra work on the glib bindings, you'd even be
able to run SVG canvas from python (whereas at the moment, you'd have
to do it as javascript fragments).

the moral of the story is that web browser technology makes for a hell
of a lot better widget set than a desktop-designed widget set does.  a
_lot_ better.  there's been far more effort put into it, for a start.
browsers are designed to make the content look "readable" in far more
circumstances - hostile and conflicting circumstances - than desktop
apps are.  we stare at browsers far more than we do at desktop apps,
for the most part.

and so, you get things like text flowing neatly around, and even
widgets flowing neatly.  _properly_.  you can even specify, thanks to
CSS styling, whether you want the "flowing" to be vertical-first or
horizontal-first.

imagine trying to implement that with GTK2 or QT4 - it'd be a
_nightmare_ gone wrong.  yet, browsers have been doing text-flowing
and div-flowing for... forever.

now, at this point, having got what i wanted, i didn't want to spend
time on wxWidgets, but i can imagine that there would be similar
limitations.

the issue with implementing a widget set is that there is a very
specific set of functionality that is absolutely absolutely required,
and without every single bit of functionality, you are entirely
wasting your time to make the port.  threading.  timers.  rich text
(aka HTML).  event handling including window resize, onload, mouse
over, in, out, move; keyboard handling; asynchronous external
communication with the rest of the world.  embedded plugins.  layout
management, including horizontal, vertical, grid and flow, with
_decent_ cell proportion subdivision of available space, and respect
for minimum widths / heights as well as fixed widths / heights.

without _all_ of these things, done properly, you're hosed before you
even begin to create your widget set "wrapper".

GTK lacks flow-layout, rich text support and proportion subdivision of
layouts, making every GTK application in existence look utterly...
shit.  scuse my french.  fortunately, someone's come to the rescue
with a gtk theme engine which allows you to customise gtk with CSS
stylesheets, but it is early days yet.

_other_ than these significant failings, GTK is technically pretty
damn good and provides everything else you'd need - including
embedding flash and other plugins by leveraging mozplugger - in an
easy-to-use and well-documented fashion.

QT4 lacks crucial layout management (layouts not being deletable from
layouts), flow-layout, and variable-sized rich text.  they _do_ have
proportional subdivision of layouts (allowing you to specify a fixed
width on one cell and a percentage width on others) but it is very
clumsy.

other than those failings, which are less than those of GTK2 but as
equally significant, QT4 _looks_ better than GTK2 but ... it's still
not good _enough_.

when you've written an app with pyjamas-desktop, and it looks good no
matter whether you resize the window to 1200x800 or down to 320x800,
because you cater for onResize events and reformat the layout, _then_
you know you're on to a winner [my first ever pyjamas app was my own
web site - http://lkcl.net/site_code - see the onWindowResize
function, which adapts the site layout.  _yes_ my web site runs under
pyjd as a desktop app :) ]

and - this is the kicker: the pyjamas API itself, as long as you stick
to it, you know that the same application will run - unmodified - in a
_real_ web browser, by being compiled to javascript.

now all i have to do is investigate pydom and pyxpcomext, because -
again, porting pyjamas to utilise pydom i believe will be utterly
trivial.  if i hadn't had to cater for some of glib's foibles, with
silly naming conventions, i reckon i'd be done in about 16 hours flat
(i'll let you know how i get on, when i have 16 hours of time
available to _try_!).

oh - one last thing.  glib != gtk.  therefore, the possibility exists
to do a pywebkitqt4, a pywebkit/wxWidgets, and, also, thanks to google
chrome's use of webkit, what google have done is write their OWN
drawing library (!!!) making ANOTHER graphics-port of webkit that is
completely independent of and having nothing to do with gtk2, qt4 or
wxWidgets.  then what they have done is provide accelerated drivers
for ARM-embedded devices (in android) and another one for windows.
ripping that library (i forget its name) out of the clutches of the
monster 450mb hairy tarball that is called "google chrome" should be
given some high priority.

anyway - the reason i mention it is because with a tiny bit of messing
about, you can get a pywebkit-<anything> that is entirely and wholly
independent of the underlying "helper-widget-set" on which it sits.
the only real reason why, then, you would want to use a particular
pywebkit-<xxx> - e.g. pywebkit-qt4 with bindings to the DOM model -
would be because you wanted to embed the webkit engine into an
existing pyqt4 application.

in this way, i hope that i have highlighted that the pyjamas API is
entirely independent of the "underlying" widget set which it uses to
draw on-screen, making it a proper "cross-widget-set" API, even though
at the moment there is only widget set that it's been ported to
(pywebkitgtk).

the summary: doing a decent cross-widget-set API that is  also cross-
platform, cross-desktop, cross-browser is damn hard - but it _can_ be
done, and _has_ been done, albeit in a very roundabout and obscure
fashion.  http://pyjs.org and http://pyjd.org

l.



More information about the Python-list mailing list