blighty.x11 package¶
Module contents¶
This module provides support for creating X11 canvases. If you are trying to replicate conky’s behaviour, the API offered by this module is the closest to it.
Submodules¶
blighty.x11.canvas module¶
Description¶
This module provides the Canvas
class for the creation of X11
canvases.
The Canvas
class is, in Java terminoly, abstract and should not be
instantiated directly. Instead, applications should define their own subclasses
of the Canvas
and implement the on_draw()
method, which gets
called periodically to perform the required draw operations using pycairo.
Once created, an instance of a subclass of Canvas
can be shown on
screen by calling the show()
method. This starts drawing the canvas on
screen by calling the on_draw callback at regular intervals in time. Events
can be handled by starting the event loop with
blighty.x11.start_event_loop()
, as described in more details in the
Event handling section.
Creating a canvas¶
Canvases are created by simply subclassing the Canvas class and implementing
the on_draw()
callback.
The Canvas
constructor (i.e. the __new__()
magic method) takes
the following arguments:
Argument | Description | |
---|---|---|
x | These arguments describe the basic geometry of the canvas.
The x and y coordinates are relative to the gravity
argument (see below). The width and height arguments
give the canvas size in pixels. |
|
y | ||
width | ||
height | ||
interval | The time interval between calls to the Default value: 1000 (i.e. 1 second) |
|
screen | In multi-screen setups, specifies on which screen the canvas is to be drawn. The value 0 identifies the first screen. To treat the phisical screens as a single virtual screen, use the value -1. Default value: 0 (i.e. the first screen) |
|
window_type | The type of window to create. The possible choices are
enumerated in the Default value: |
|
gravity | Defines the coordinate system for the canvas relative to
the screen. The allowed values are enumerated in the
Default value: |
|
sticky | Whether the window should stick to the desktop and hence be visible in all workspaces. Default value: |
|
keep_below | Whether the window should stay below any other window on the screen. Default value: |
|
skip_taskbar | Whether the window should not have an entry in the taskbar. Default value: |
|
skip_pager | Whether the window should not appear in the pager. Default value: |
Note that the interval can be changed dynamically by setting the interval
attribute on the canvas object directly after it has been created.
If you want to distribute your subclasses of Canvas
, we recommend that
you create a static method build
that returns an instance of the subclass,
with some of the argumets set to a predefined values. This is useful if you
want to distribute widgets with, e.g., a predefined size, as a Python module.
Showing the canvas¶
When a canvas is created, it is not immediately shown to screen. To map it to
screen and start the draw cycle one has to call the show()
method
explicitly.
If you need to pass data to the canvas, you might want to do that before
calling this method, since presumably the on_draw()
callback, which will
start to be called, makes use of it.
Finally, you must start the main event loop with
blighty.x11.start_event_loop()
to start drawing on the canvases, and in
case that they should handle input events, like mouse button clicks or key
presses. Note however that execution in the current thread will halt at this
call, until it returns after a call to blighty.x11.stop_event_loop()
.
For more details on how to handle events with your X11 canvases, see the section Event handling below.
Disposing of a canvas¶
If you want to programmatically dispose of a canvas, you can call the
dispose()
method. This doesn’t destroy the canvas immediately, but sends
a delete request to the main event loop instead. This is the preffered way of
getting rid of a canvas when you are running the event loop. You can also use
the destroy()
method directly, which destroys the canvas immediately.
However this is not thread safe and should not be called in the on_draw()
callback when running the event loop.
Event handling¶
A feature that distinguishes blighty from conky is that it allows you to handle simple user input on the canvases. Currently, X11 canvases support two events: mouse button and key press events.
Mouse button events can be handled by implementing the
on_button_pressed()
callback in the subclass of Canvas
. The
signature is the following:
def on_button_pressed(self, button, state, x, y):
and the semantics of the arguments is the same as the XButtonEvent
[1].
To handle key presses, implement the on_key_pressed
callback with the
following signature:
def on_key_pressed(self, keysym, state):
The state
argument has the same semantics as in the
on_button_pressed()
case, while the keysym
is described, e,g, in the
Keyboard Econding section of the
Xlib guide.
A simple example¶
Here is a simple example that shows all the above concepts in action:
from blighty import CanvasGravity
from blighty.x11 import Canvas, start_event_loop
class MyCanvas(Canvas):
@staticmethod
def build(x, y):
return MyCanvas(x, y, 200, 200, gravity = CanvasGravity.NORTH)
def on_button_pressed(self, button, state, x, y):
if button == 1: # Left mouse button pressed
self.dispose()
def on_draw(self, ctx):
ctx.set_source_rgb(1, 0, 0)
ctx.rectangle(0, 0, ctx.canvas.width >> 1, ctx.canvas.height >> 1)
ctx.fill()
if __name__ == "__main__":
# Instantiate the canvas
canvas = MyCanvas.build()
# Map it on screen
canvas.show()
# Start the event loop
start_event_loop()
Extra features¶
The Canvas
class comes with some handy extra features that can help
with common patterns, thus sparing you to have to type boilerplate code.
Brushes¶
Brushes are a way to rebind methods from your subclass of Canvas
to
the Cairo context. Consider the following example:
from random import random as r
class RectCanvas(blighty.x11.Canvas):
def rect(self, ctx, width, height):
ctx.set_source_rgb(*[r() for _ in range(3)])
ctx.rectangle(0, 0, width, height)
ctx.fill()
def on_draw(self, ctx):
for i in range(4):
self.rect(ctx, self.width >> i, self.height >> i)
The method rect
is defined under the class RectCanvas
for convenience.
However, from a logical point of view, it would make more sense for this method
to belong to ctx
, since the general pattern of these helper methods
requires that we pass ctx
as one of the arguments.
If one prefixes the rect
method with draw_
then it turns into an
implicit brush. The on_draw()
callback is called with the ctx
argument being an instance of ExtendedContext
. The draw_rect
brush is
then available from ctx
as a bound method. The sample code above can then
be refactored as:
from random import random as r
class RectCanvas(blighty.x11.Canvas):
def draw_rect(ctx, width, height):
ctx.set_source_rgb(*[r() for _ in range(3)])
ctx.rectangle(0, 0, width, height)
ctx.fill()
def on_draw(self, ctx):
for i in range(4):
ctx.rect(self.width >> i, self.height >> i)
Notice how draw_rect
now takes less arguments, and how the first one is
ctx
, the (extended) Cairo context.
If you do not wish to prefix your methods with draw_
, you can use the
blighty.brush()
decorator instead to create an explicit brush. The code
would then look like this:
from blighty import brush
from random import random as r
class RectCanvas(blighty.x11.Canvas):
@brush
def rect(ctx, width, height):
ctx.set_source_rgb(*[r() for _ in range(3)])
ctx.rectangle(0, 0, width, height)
ctx.fill()
def on_draw(self, ctx):
for i in range(4):
ctx.rect(self.width >> i, self.height >> i)
Text alignment¶
A common task is writing text on a canvas. With Cairo, text alignment usually
requires the same pattern: get the text extents and compute the new position.
To help with that, Canvas
objects come with a pre-defined
write_text()
brush. Please refer to the API documentation below for usage
details.
Grid¶
When designing a canvas from scrach, it is hard to guess at positions without
any guiding lines. To help with precise placement, every Canvas
object
comes with a draw_grid
brush that creates a rectangular grid on the canvas.
The spacing between the lines is set to 50 pixels by default (assuming that
the scale hasn’t been changed before). This can be adjusted by passing the new
spacing along the two directions as arguments. Please refer to the API
documentation below for more details.
References
[1] | https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html |
Module API¶
-
class
blighty.x11.canvas.
Canvas
(*args, **kwargs)[source]¶ Bases:
x11.BaseCanvas
X11 Canvas object.
This class is meant to be used as a superclass and should not be instantiated directly. Subclasses should implement the
on_draw()
callback, which is invoked every time the canvas needs to be redrawn. Redraws happen at regular intervals in time, as specified by theinterval
attribute (also passed as an argument via the constructor).-
dispose
()¶ Mark the canvas as ready to be destroyed to free up resources.
-
draw_grid
(x=50, y=50)[source]¶ Draw a grid on the canvas [implicit brush].
This implicit brush method is intended to help with determining the location of points on the canvas during development.
Parameters:
-
get_size
()¶ Get the canvas size.
Returns: the 2-tuple of width and height in pixels. Return type: tuple
-
height
¶ The canvas height. Read-only.
-
interval
¶ The refresh interval, in milliseconds.
-
move
()¶ Move the canvas to new coordinates.
The x and y coordinates are relative to the canvas gravity.
-
on_draw
(ctx)[source]¶ Draw callback.
Once the
show()
method is called on aCanvas
object, this method gets called at regular intervals of time to perform the draw operation. Every subclass ofCanvas
must implement this method.
-
show
()¶ Map the canvas to screen and set it ready for drawing.
-
width
¶ The canvas width. Read-only.
-
write_text
(x, y, text, align=3)[source]¶ Write aligned text [explicit brush].
This explicit brush method helps write aligned text on the canvas. The x and y coordinates are relative to the specified alignment. By default, this is
blighty.TextAlign.TOP_LEFT
, meaning that the text will be left-aligned and on top of the horizontal line that passes through y on the vertical axis. In terms of the point (x,y) on the Canvas, the text will develop in the NE direction.The return value is the text extents, in case that some further draw operations depend on the space required by the text to be drawn on the canvas.
Note that font face and size need to be set on the Cairo context prior to a call to this method.
Parameters: Returns: The same return value as
cairo.text_extents
.Return type:
-
x
¶ The canvas x coordinate. Read-only.
-
y
¶ The canvas y coordinate. Read-only.
-