
ooxcb Documentation Release 1.2 samurai-x.org February 12, 2014 Contents i ii ooxcb Documentation, Release 1.2 Contents: Contents 1 ooxcb Documentation, Release 1.2 2 Contents CHAPTER 1 Introduction 1.1 What is ooxcb? ooxcb (the object oriented X C binding, yes, the C doesn’t fit here) is a new Python binding to the X server, developed for the samurai-x window manager. xpyb uses a wrapper generator to create python modules out of the XML X protocol descriptions of the xcb project. It aims to provide with an easy-to-use object-oriented interface to the X server. 1.2 Why? There already is a similar project called xpyb which is able to create an usable Python module for every X extension supported by xcb-proto. However, the most important parts of xpyb are in a C extension, and we wanted samurai-x to be pure-python. So we ported the whole C code of xpyb to Python, just using some functions of the libxcb API invoked by the ctypes module (you can get it here, but beware: it’s a bit unstable). Apart from that, xpyb-generated bindings are very close to the X protocol. For every extension, you have one class that has some methods for each request. On the one hand, xpyb is able to cover all the extensions supported by xcb-proto this way; on the other hand, the binding is not very comfortable to use. Because of that, we decided to write our own binding, based on the xpyb-ctypes code (so, big thanks to xpyb!). The ooxcb wrapper generator uses so-called interface files that describe the desired Python API of a specific extension - so we can create an API that is more comfortable and easy-to-use. However, someone has to write these interface files, and depending on the size and complexity of the extension, that’s a time-intensive job. At the moment, everything of the xproto extension (the core extension) is wrapped, but some parts need testing. The xtest extension is already usable, too. Additionally, ooxcb comes with a simple and powerful event dispatching system (stolen from pyglet) - you don’t have to use it necessarily, but it can make life much easier. 1.3 How does it look? Here’s a minimal example that displays a white window and exits if a mouse button is pressed: import sys import ooxcb from ooxcb.protocol.xproto import * conn= ooxcb.connect() 3 ooxcb Documentation, Release 1.2 screen= conn.setup.roots[conn.pref_screen] win= Window.create_toplevel_on_screen(conn, screen, back_pixel=screen.white_pixel, event_mask=EventMask.Exposure| EventMask.ButtonPress ) with conn.bunch(): win.configure(width=100) win.map() @win.event def on_button_press(evt): print ’Button pressed, exiting!’ conn.disconnect() sys.exit() while True: try: conn.wait_for_event().dispatch() except ooxcb.ProtocolException, error: print "Protocol error %s received!"% error.__class__.__name__ break conn.disconnect() 1.4 Is it usable? As said above, the xproto extension is already wrapped, and ooxcb is relatively stable, so it should be possible to use it (we are already using it for samurai-x). If you stumble upon bugs, please report them on the bug tracker. 4 Chapter 1. Introduction CHAPTER 2 Getting Started The following tries to be something like a tutorial for ooxcb programming. It requires a bit of knowledge of the X concept, but I tried to keep it simple. Please contact us if you have any suggestions. You can find the final version of this application in your source distribution in examples/gettingstarted.py or online here. Please don’t forget the api documentation! So, let’s start: If you want to use ooxcb in your application, you first have to import it. You also need to import a module that provides with a core protocol implementation. That’s most likely the ooxcb.protocol.xproto module: import sys import ooxcb from ooxcb.protocol import xproto The second import registers the xproto module as core module, so that import is necessary. Then, you will want to establish a connection to the X server. That is done using the ooxcb.connect() method: conn= ooxcb.connect() That connects to the default X display, specified by the DISPLAY environment variable. You could also connect to another display: conn= ooxcb.connect(’:1’) See the api documentation on ooxcb.connect() for more details. At the end of the script, we do disconnect cleanly: conn.disconnect() That’s not really required, but recommended. So, after you have established a connection, you will most likely want to get some information about the available screens. You can get the connection setup information by accessing the setup property of the connection: setup= conn.setup # That’s equivalent to setup= conn.get_setup() There’s exactly no difference between the two calls, the setup information are cached in any case. You can see all attributes of the setup here: ooxcb.Setup (not really documented, however). You can access the screens (there is often only one) by the attribute roots. And there is a pref_screen attribute on the connection that is the preferred screen index: 5 ooxcb Documentation, Release 1.2 screen= conn.setup.roots[conn.pref_screen] Yay. We have a screen. Now, if we want to create a window on this screen, that looks complicated, but it isn’t (really!). window= xproto.Window.create(conn, screen.root, screen.root_depth, screen.root_visual ) That’s the easiest call possible. It will create a window with the screen’s root window as parent, its root depth as depth and its root visual as visual. Fortunately, there is a shortcut for this boilerplate code: window= xproto.Window.create_toplevel_on_screen(conn, screen) Woah! So easy! These two calls will create a new (unmapped: invisible) window with the root window as parent: a top-level window. It will be 640x480 pixels huge, have no border and be located at the top left edge of the screen (x=0, y=0). Now ... window.map() print conn.wait_for_event() Shouldn’t this display a window? Why doesn’t it do? It just does nothing and doesn’t even stop! killall python helps, but ... how to fix it? As Christophe Tronche explains in his awesome “Short Xlib Tutorial” (worth reading!), we need to flush after we have done a bunch of requests. They are cached until you check a request or call flush, then all cached requests will be delivered. So, change the lines above to: window.map() conn.flush() print conn.wait_for_event() As a convenience function, you can also use ooxcb.conn.Connection.bunch() in a with stament. After the execution of the with block, the connection gets flushed. with conn.bunch(): window.map() print conn.wait_for_event() Of course, that makes more sense if you have more requests at a time. And - the window appears, but with ‘nothing in it’. We actually want to see something, and so we’ll set the background color of the window to plain white. That is done by modifying the window creation line: window= xproto.Window.create_toplevel_on_screen(conn, screen, back_pixel=screen.white_pixel) And - it has a white background. Awesome! Now, before we can start to draw anything here, we have to talk about events. We are communiating with the X server, and the X server is communicating with us. We send requests, he sends responses. And sometimes, he sends events. It is possible to handle events in an Xlib style here: while 1: evt = conn.wait_for_event() if isinstance(evt, xproto.ExposeEvent): print ’Got an expose event!’ elif ... 6 Chapter 2. Getting Started ooxcb Documentation, Release 1.2 But ooxcb also comes with an event dispatching framework, and it is very convenient to use because you don’t have to figure out who has to handle the event yourself. @window.event def on_expose(evt): print ’Got an expose event for %s!’% repr(window) while 1: conn.wait_for_event().dispatch() So, on_expose is called only if window is exposed. To draw in the window at the right time, we will register for the expose event and draw if we receive one. We first have to register for the expose events to receive any. Don’t forget to register for events! We can do that in the window creation line, too: window= xproto.Window.create_toplevel_on_screen(conn, screen, back_pixel=screen.white_pixel, event_mask=xproto.EventMask.Exposure ) Now, let’s listen to expose events. We have a new mainloop now: @window.event def on_expose(evt): " drawing here ..." # Our mainloop. while 1: conn.wait_for_event().dispatch() Now, if we want to draw something in the window now, we need a graphics context first. A graphics context is required for drawing anything on a drawable. Fortunately, a window is a drawable, so it is rather easy to start. Put the following in the beginning of the script: gc= xproto.GContext.create(conn, window) We will draw a line from (0, 0) to (640, 480) now. A diagonal line through the whole window. Put it in on_expose: @window.event def on_expose(evt): gc.poly_line(window, [(0,0), (640, 480)]) conn.flush() You see, we are giving poly_line a list of tuples of (x, y) here. That’s useful if we want to draw multiple lines at once, e.g. a triangle: gc.poly_line(window, [(10, 10), (600, 400), (10, 400), (10, 10)]) conn.flush() Also note that we have to pass window to each drawing function again. Don’t forget that. And don’t forget to flush. Well, we have a very cool triangle now. But if we click on the tiny X to close the window, we get a very bad “IOError: I/O error on X server connection.” exception.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages171 Page
-
File Size-