Posts

Showing posts with the label gtk

Desktop Widgets with PyGTK, Launchpad Remote Control

Image
""" Desktop Widgets with PyGTK, Launchpad Remote Control We shall today be looking at a dumb hack I glanced upon while foolishly reading the list of GDK Constants in the PyGTK documentation. This hack sets the type hint of a GTK Window instance (the thing that tells the window manager how to treat it) as a desktop window, and hence embeds the thing in the desktop. It even works quite well: The window and widgets appear in the desktop The widgets are raised when the "Show desktop" command happens The widgets appear on all desktops (in Gnome and XFCE4, but not in KDE) The widgets appear fully functional So I got all excited and tried to think of an awesome use-case as the first plugin for a new kind of desktop widget framework. One which couldn't care less about eye-candy, and focussed on truly functional and useful desktop-based applets. As a friend commented while I was discussing the idea: "I am often hacking away in emacs when I decide that I want to...

Spawning subprocess with PyGTK using Twisted

Well, it is an age-old problem: How to schedule long-running tasks withing a GUI main loop (in our case PyGTK). There are a few ways: Use Python's subprocess module and select on the pipe with gobject's io_add_watch Use GTK's built in subprocess spawning abilities Use Twisted 1 & 2 are reasonable approaches, and they both work. Of course 1 won't work on Win32. The only problem with both 1 & 2 is that they use gobject's polling functions to achieve asynchronicity. This is nice when we are forced in a PyGTK main loop, but really not nice when the application wants to run in command line mode, and we really want to be able to share the execution code between different UIs, including perhaps other toolkits. Enter Twisted. We need to do two things with Twisted: Make sure Twisted knows we are running with PyGTK Launch the process Making sure Twisted knows that we are running inside PyGTK is quite easy (though I imagine the implementation was painful). To do this, ...

Kiwi proxy widgets, a common widget API

Image
While we are on the notion of Kiwi , the PyGTK helper library, we should be discussing the proxy widgets. They offer a certain set of advantages over their plain PyGTK counterparts: They have a common signal emission API for change in content They offer a common API for setting and reading their value. They offer validation, and coercion They contain a few general improvements over the plain PyGTK widgets What does this mean? Simply it means you can make any data widget (eg Entry, CheckButton, Combo etc), you can connect its signal "content-changed", you can read the data with widget.read(), and set the value with widget.update(). If you have read any of the previous blogs about adapting Zope.schema fields to widgets, and you are alert, you will notice that this is amazingly useful. It means that we can define an interface for a general InputWidget type, something like: class IInputWidget(Interface): def read(): """Read the value in the widget"""...

PyGTK lists made easy with Kiwi

Image
Making nice lists is an utter pain with PyGTK. GTK+ does you the pleasure of separating the model and the view. I guess it is a reasonable idea in theory (don't they always teach you to separate the model and the view?) and allows you to have alternative views of the same model, and allows you to extend the implementation in any sort of way. BUT, to repeat: in most cases it is an utter pain. Even the simplest list becomes a mess of boilerplate code. Anyone who has done a decent amount of PyGTK programming will have written their own implementation of model+view mixed together, but the best one I have used is from Kiwi. If you have never used it, Kiwi is a framework that lessens some of the painful aspects of PyGTK development. In fact, it's so useful, let's call it a library. Creating a pythonic view of a list of objects is easy. Let's have a look at some code: from kiwi.ui.objectlist import ObjectList, Column class Fruit(object): def __init__(self, name, is_red): self...