aioxlib 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aioxlib-0.4.0 → aioxlib-0.5.0}/PKG-INFO +4 -2
- {aioxlib-0.4.0 → aioxlib-0.5.0}/README.md +3 -1
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/__init__.py +4 -7
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/_extensions.py +2 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/api.py +8 -2
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/connection.py +0 -4
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/display.py +48 -7
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/protocol.py +76 -0
- aioxlib-0.5.0/aioxlib/randr.py +1350 -0
- aioxlib-0.5.0/aioxlib/widgets.py +211 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib.egg-info/PKG-INFO +4 -2
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib.egg-info/SOURCES.txt +2 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_connection.py +0 -16
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/authority.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/bigreq.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/constants.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/dbe.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/dri3.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/glx.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/present.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/render.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib/shm.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib.egg-info/dependency_links.txt +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/aioxlib.egg-info/top_level.txt +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/pyproject.toml +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/setup.cfg +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_api.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_authority.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_bigreq.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_constants.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_dbe.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_display.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_dri3.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_examples.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_glx.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_present.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_protocol.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_render.py +0 -0
- {aioxlib-0.4.0 → aioxlib-0.5.0}/tests/test_shm.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aioxlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Human friendly interface to XLib subsystems using asyncio python
|
|
5
5
|
Author-email: Jose Tiago Macara Coutinho <coutinhotiago@gmail.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -36,10 +36,12 @@ asyncio—without blocking the event loop and without linking to libX11.
|
|
|
36
36
|
## Documentation
|
|
37
37
|
|
|
38
38
|
- Online: [aioxlib.readthedocs.io](https://aioxlib.readthedocs.io)
|
|
39
|
-
- Local: `pip install
|
|
39
|
+
- Local: `pip install --group docs && mkdocs serve`
|
|
40
40
|
|
|
41
41
|
## Installation
|
|
42
42
|
|
|
43
|
+
From within your favorite python environment:
|
|
44
|
+
|
|
43
45
|
```bash
|
|
44
46
|
pip install aioxlib
|
|
45
47
|
```
|
|
@@ -12,10 +12,12 @@ asyncio—without blocking the event loop and without linking to libX11.
|
|
|
12
12
|
## Documentation
|
|
13
13
|
|
|
14
14
|
- Online: [aioxlib.readthedocs.io](https://aioxlib.readthedocs.io)
|
|
15
|
-
- Local: `pip install
|
|
15
|
+
- Local: `pip install --group docs && mkdocs serve`
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
19
|
+
From within your favorite python environment:
|
|
20
|
+
|
|
19
21
|
```bash
|
|
20
22
|
pip install aioxlib
|
|
21
23
|
```
|
|
@@ -16,19 +16,16 @@ Types and protocol helpers live in submodules::
|
|
|
16
16
|
from aioxlib.protocol import pack_create_window
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
__version__ = "0.
|
|
19
|
+
__version__ = "0.5.0"
|
|
20
20
|
|
|
21
|
+
from . import api, constants
|
|
21
22
|
from .api import * # noqa: F403
|
|
22
|
-
from .api import __all__ as _api_all
|
|
23
23
|
from .constants import * # noqa: F403
|
|
24
|
-
from .constants import __all__ as _constants_all
|
|
25
24
|
from .display import get_display
|
|
26
25
|
|
|
27
26
|
__all__ = [
|
|
28
27
|
"__version__",
|
|
29
28
|
"get_display",
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
*constants.__all__,
|
|
30
|
+
*api.__all__,
|
|
32
31
|
]
|
|
33
|
-
|
|
34
|
-
del _api_all, _constants_all
|
|
@@ -11,6 +11,7 @@ from .dbe import DoubleBuffer
|
|
|
11
11
|
from .dri3 import DRI3
|
|
12
12
|
from .glx import GLX
|
|
13
13
|
from .present import Present
|
|
14
|
+
from .randr import RandR
|
|
14
15
|
from .render import Render
|
|
15
16
|
from .shm import SharedMemory
|
|
16
17
|
|
|
@@ -22,4 +23,5 @@ EXTENSIONS = {
|
|
|
22
23
|
"DRI3": DRI3,
|
|
23
24
|
"Present": Present,
|
|
24
25
|
"RENDER": Render,
|
|
26
|
+
"RANDR": RandR,
|
|
25
27
|
}
|
|
@@ -207,6 +207,11 @@ async def get_font_path(display: Display | None = None):
|
|
|
207
207
|
return await d.get_font_path()
|
|
208
208
|
|
|
209
209
|
|
|
210
|
+
async def set_font_path(path, display: Display | None = None):
|
|
211
|
+
d = await _resolve_display(display)
|
|
212
|
+
return await d.set_font_path(path)
|
|
213
|
+
|
|
214
|
+
|
|
210
215
|
async def get_atom(name, only_if_exists=False, display: Display | None = None):
|
|
211
216
|
"""Intern *name* (with cache) on the default (or given) display."""
|
|
212
217
|
d = await _resolve_display(display)
|
|
@@ -296,10 +301,10 @@ async def open_font_name(name, display: Display | None = None):
|
|
|
296
301
|
return await d.open_font_name(name)
|
|
297
302
|
|
|
298
303
|
|
|
299
|
-
async def open_font(display: Display | None = None, **kwargs):
|
|
304
|
+
async def open_font(name=None, display: Display | None = None, **kwargs):
|
|
300
305
|
"""Open a font built from keyword XLFD fields."""
|
|
301
306
|
d = await _resolve_display(display)
|
|
302
|
-
return await d.open_font(**kwargs)
|
|
307
|
+
return await d.open_font(name=name, **kwargs)
|
|
303
308
|
|
|
304
309
|
|
|
305
310
|
async def tree(wnd, display: Display | None = None):
|
|
@@ -402,6 +407,7 @@ __all__ = [
|
|
|
402
407
|
"query_extension",
|
|
403
408
|
"list_fonts",
|
|
404
409
|
"get_font_path",
|
|
410
|
+
"set_font_path",
|
|
405
411
|
"get_atom",
|
|
406
412
|
"default_screen",
|
|
407
413
|
"create_window",
|
|
@@ -41,12 +41,15 @@ from .protocol import (
|
|
|
41
41
|
pack_change_property,
|
|
42
42
|
pack_clear_area,
|
|
43
43
|
pack_configure_window,
|
|
44
|
+
pack_copy_area,
|
|
44
45
|
pack_create_colormap,
|
|
45
46
|
pack_create_gc,
|
|
47
|
+
pack_create_pixmap,
|
|
46
48
|
pack_create_window,
|
|
47
49
|
pack_delete_property,
|
|
48
50
|
pack_destroy_window,
|
|
49
51
|
pack_free_colormap,
|
|
52
|
+
pack_free_pixmap,
|
|
50
53
|
pack_get_atom_name,
|
|
51
54
|
pack_get_font_path,
|
|
52
55
|
pack_get_geometry,
|
|
@@ -69,12 +72,14 @@ from .protocol import (
|
|
|
69
72
|
pack_query_extension,
|
|
70
73
|
pack_query_tree,
|
|
71
74
|
pack_reparent_window,
|
|
75
|
+
pack_set_font_path,
|
|
72
76
|
pack_set_input_focus,
|
|
73
77
|
pack_setup,
|
|
74
78
|
pack_unmap_window,
|
|
75
79
|
unpack_client_message,
|
|
76
80
|
unpack_error,
|
|
77
81
|
unpack_event,
|
|
82
|
+
unpack_expose_event,
|
|
78
83
|
unpack_get_atom_name,
|
|
79
84
|
unpack_get_font_path,
|
|
80
85
|
unpack_get_geometry,
|
|
@@ -155,6 +160,7 @@ class Drawable(Resource):
|
|
|
155
160
|
|
|
156
161
|
async def draw_image(self, gc, x, y, w, h, depth, data, drawable=None):
|
|
157
162
|
"""Draw image."""
|
|
163
|
+
drawable = drawable or self
|
|
158
164
|
max_size = self.display.info["max_request_length"]
|
|
159
165
|
nb_pixels = w * h
|
|
160
166
|
n = len(data)
|
|
@@ -194,8 +200,7 @@ class Drawable(Resource):
|
|
|
194
200
|
|
|
195
201
|
async def put_text(self, gc, x, y, text, drawable=None):
|
|
196
202
|
"""Put text."""
|
|
197
|
-
|
|
198
|
-
drawable = self
|
|
203
|
+
drawable = drawable or self
|
|
199
204
|
payload = pack_image_text(drawable, gc, x, y, text)
|
|
200
205
|
self.display.connection.write(payload)
|
|
201
206
|
|
|
@@ -203,6 +208,11 @@ class Drawable(Resource):
|
|
|
203
208
|
"""Get geometry."""
|
|
204
209
|
return await self.display.get_geometry(self)
|
|
205
210
|
|
|
211
|
+
async def create_pixmap(self, width, height, depth=None, drawable=None):
|
|
212
|
+
"""Create a pixmap. *drawable* defaults to the root window."""
|
|
213
|
+
drawable = drawable or self
|
|
214
|
+
return await self.display.create_pixmap(width, height, depth, drawable)
|
|
215
|
+
|
|
206
216
|
|
|
207
217
|
class ResourceManager:
|
|
208
218
|
"""Allocates resource IDs from the server base and mask."""
|
|
@@ -284,7 +294,7 @@ class Window(Drawable):
|
|
|
284
294
|
delete_on_close=False,
|
|
285
295
|
take_focus=False,
|
|
286
296
|
**attrs,
|
|
287
|
-
):
|
|
297
|
+
) -> Window:
|
|
288
298
|
"""Create window."""
|
|
289
299
|
wid = self.display.resources.allocate()
|
|
290
300
|
payload = pack_create_window(
|
|
@@ -482,7 +492,7 @@ class Screen:
|
|
|
482
492
|
background_pixel=None,
|
|
483
493
|
delete_on_close=True,
|
|
484
494
|
**attrs,
|
|
485
|
-
):
|
|
495
|
+
) -> Window:
|
|
486
496
|
"""Create window."""
|
|
487
497
|
if parent is None:
|
|
488
498
|
parent = self.root
|
|
@@ -538,7 +548,10 @@ class Display:
|
|
|
538
548
|
self.commands = {cmd: cmd.name for cmd in Command}
|
|
539
549
|
self.requests = asyncio.Queue()
|
|
540
550
|
self.listeners = set()
|
|
541
|
-
self._events = {
|
|
551
|
+
self._events = {
|
|
552
|
+
EventType.ClientMessage: unpack_client_message,
|
|
553
|
+
EventType.Expose: unpack_expose_event,
|
|
554
|
+
}
|
|
542
555
|
self._atom_cache = {}
|
|
543
556
|
self._extensions_cache = None
|
|
544
557
|
self._task = None
|
|
@@ -670,6 +683,16 @@ class Display:
|
|
|
670
683
|
reply = await self.write_read(payload, unpack_get_font_path)
|
|
671
684
|
return reply["path"]
|
|
672
685
|
|
|
686
|
+
async def set_font_path(self, paths=()):
|
|
687
|
+
"""Set the font search path.
|
|
688
|
+
|
|
689
|
+
*paths* is a sequence of directory strings. Pass an empty sequence
|
|
690
|
+
(or call with no arguments) to restore the server default path.
|
|
691
|
+
This is a write-only request (no reply).
|
|
692
|
+
"""
|
|
693
|
+
payload = pack_set_font_path(paths)
|
|
694
|
+
self.write(payload)
|
|
695
|
+
|
|
673
696
|
async def get_atom(self, name, only_if_exists=False):
|
|
674
697
|
"""Intern *name* and cache the atom id."""
|
|
675
698
|
if name in self._atom_cache:
|
|
@@ -759,9 +782,9 @@ class Display:
|
|
|
759
782
|
self.write(payload)
|
|
760
783
|
return fid
|
|
761
784
|
|
|
762
|
-
async def open_font(self, **kwargs):
|
|
785
|
+
async def open_font(self, name=None, **kwargs):
|
|
763
786
|
"""Open font."""
|
|
764
|
-
font = build_font(**kwargs)
|
|
787
|
+
font = build_font(**kwargs) if name is None else name
|
|
765
788
|
return await self.open_font_name(font)
|
|
766
789
|
|
|
767
790
|
async def tree(self, wnd):
|
|
@@ -811,6 +834,24 @@ class Display:
|
|
|
811
834
|
payload = pack_clear_area(wnd, x, y, w, h, exposure)
|
|
812
835
|
self.write(payload)
|
|
813
836
|
|
|
837
|
+
async def copy_area(self, src, dst, gc, src_x, src_y, width, height, dst_x=0, dst_y=0):
|
|
838
|
+
"""Copy a rectangle from *src* to *dst*."""
|
|
839
|
+
self.write(pack_copy_area(src, dst, gc, src_x, src_y, width, height, dst_x, dst_y))
|
|
840
|
+
|
|
841
|
+
async def create_pixmap(self, width, height, depth=None, drawable=None):
|
|
842
|
+
"""Create a pixmap. *drawable* defaults to the root window."""
|
|
843
|
+
if drawable is None:
|
|
844
|
+
drawable = self.default_screen().root
|
|
845
|
+
if depth is None:
|
|
846
|
+
depth = self.default_screen().root_depth
|
|
847
|
+
pid = self.resources.allocate()
|
|
848
|
+
self.write(pack_create_pixmap(pid, drawable, width, height, depth))
|
|
849
|
+
return pid
|
|
850
|
+
|
|
851
|
+
async def free_pixmap(self, pixmap):
|
|
852
|
+
"""Free a pixmap."""
|
|
853
|
+
self.write(pack_free_pixmap(pixmap))
|
|
854
|
+
|
|
814
855
|
async def set_input_focus(self, focus, revert_to=1, time=0):
|
|
815
856
|
"""Set keyboard input focus to *focus* (window id or resource)."""
|
|
816
857
|
self.write(pack_set_input_focus(focus, revert_to=revert_to, time=time))
|
|
@@ -359,6 +359,36 @@ def unpack_list_properties(data, offset=0):
|
|
|
359
359
|
return struct.unpack_from(f"{nb_atoms}I", data, offset), offset + nb_atoms * 4
|
|
360
360
|
|
|
361
361
|
|
|
362
|
+
def pack_list_strings(strings, encoding=DEFAULT_STRING_ENCODING) -> bytes:
|
|
363
|
+
"""Pack a LISTofSTR (length-prefixed strings) with trailing pad to 4 bytes."""
|
|
364
|
+
parts = []
|
|
365
|
+
total = 0
|
|
366
|
+
for s in strings:
|
|
367
|
+
if isinstance(s, str):
|
|
368
|
+
b = s.encode(encoding)
|
|
369
|
+
else:
|
|
370
|
+
b = bytes(s)
|
|
371
|
+
if len(b) > 255:
|
|
372
|
+
raise ValueError(f"font path component longer than 255 bytes: {s!r}")
|
|
373
|
+
parts.append(struct.pack("B", len(b)) + b)
|
|
374
|
+
total += 1 + len(b)
|
|
375
|
+
body = b"".join(parts)
|
|
376
|
+
return body + b"\0" * pad(total)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def pack_set_font_path(paths=()) -> bytes:
|
|
380
|
+
"""Pack a SetFontPath request.
|
|
381
|
+
|
|
382
|
+
*paths* is a sequence of directory strings (or bytes). An empty sequence
|
|
383
|
+
resets the font search path to the server default.
|
|
384
|
+
"""
|
|
385
|
+
body = pack_list_strings(paths)
|
|
386
|
+
n = len(paths)
|
|
387
|
+
# header: opcode, unused, length, n, unused
|
|
388
|
+
length = 2 + len(body) // 4
|
|
389
|
+
return struct.pack("BxHH2x", Command.SetFontPath, length, n) + body
|
|
390
|
+
|
|
391
|
+
|
|
362
392
|
def pack_get_font_path():
|
|
363
393
|
"""Pack a wire-protocol get font path request into ``bytes``."""
|
|
364
394
|
return struct.pack("BxH", Command.GetFontPath, 1)
|
|
@@ -560,6 +590,15 @@ def unpack_setup_error(data, offset=0):
|
|
|
560
590
|
return error, offset + length
|
|
561
591
|
|
|
562
592
|
|
|
593
|
+
def unpack_expose_event(data, offset=0):
|
|
594
|
+
fmt = "BxHIHHHHH"
|
|
595
|
+
fields = "raw_code", "sequence_number", "window", "x", "y", "width", "height", "count"
|
|
596
|
+
reply = struct.unpack_from(fmt, data, offset)
|
|
597
|
+
result = dict(zip(fields, reply, strict=True))
|
|
598
|
+
result["name"] = EventType.Expose.name
|
|
599
|
+
return result, offset + 32
|
|
600
|
+
|
|
601
|
+
|
|
563
602
|
def unpack_event(event_map, data: bytes, offset: int = 0):
|
|
564
603
|
"""Unpack a event reply or event from *data* starting at *offset*."""
|
|
565
604
|
raw_event_type = data[0]
|
|
@@ -641,6 +680,43 @@ def pack_clear_area(wnd, x, y, w, h, exposure=False):
|
|
|
641
680
|
return struct.pack("BBHIhhHH", Command.ClearArea, int(exposure), 4, wnd, x, y, w, h)
|
|
642
681
|
|
|
643
682
|
|
|
683
|
+
def pack_copy_area(src, dst, gc, src_x, src_y, width, height, dst_x, dst_y):
|
|
684
|
+
"""Pack CopyArea."""
|
|
685
|
+
return struct.pack(
|
|
686
|
+
"BxHIIIhhhhHH",
|
|
687
|
+
Command.CopyArea,
|
|
688
|
+
7,
|
|
689
|
+
int(src),
|
|
690
|
+
int(dst),
|
|
691
|
+
int(gc),
|
|
692
|
+
int(src_x),
|
|
693
|
+
int(src_y),
|
|
694
|
+
int(dst_x),
|
|
695
|
+
int(dst_y),
|
|
696
|
+
int(width),
|
|
697
|
+
int(height),
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def pack_create_pixmap(pid, drawable, width, height, depth):
|
|
702
|
+
"""Pack CreatePixmap."""
|
|
703
|
+
return struct.pack(
|
|
704
|
+
"BBHIIHH",
|
|
705
|
+
Command.CreatePixmap,
|
|
706
|
+
int(depth),
|
|
707
|
+
4,
|
|
708
|
+
int(pid),
|
|
709
|
+
int(drawable),
|
|
710
|
+
int(width),
|
|
711
|
+
int(height),
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def pack_free_pixmap(pixmap):
|
|
716
|
+
"""Pack FreePixmap."""
|
|
717
|
+
return struct.pack("BxHI", Command.FreePixmap, 2, int(pixmap))
|
|
718
|
+
|
|
719
|
+
|
|
644
720
|
def pack_change_property(wid, property, property_type, format, data, mode):
|
|
645
721
|
"""Pack a wire-protocol change property request into ``bytes``."""
|
|
646
722
|
if not isinstance(data, bytes | bytearray):
|