aioxlib 0.3.0__tar.gz → 0.4.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.3.0 → aioxlib-0.4.0}/PKG-INFO +6 -2
- {aioxlib-0.3.0 → aioxlib-0.4.0}/README.md +5 -1
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/__init__.py +1 -1
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/display.py +49 -34
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/glx.py +96 -22
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/protocol.py +8 -6
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib.egg-info/PKG-INFO +6 -2
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_glx.py +4 -4
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/_extensions.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/api.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/authority.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/bigreq.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/connection.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/constants.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/dbe.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/dri3.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/present.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/render.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib/shm.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib.egg-info/SOURCES.txt +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib.egg-info/dependency_links.txt +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/aioxlib.egg-info/top_level.txt +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/pyproject.toml +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/setup.cfg +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_api.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_authority.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_bigreq.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_connection.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_constants.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_dbe.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_display.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_dri3.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_examples.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_present.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_protocol.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.0}/tests/test_render.py +0 -0
- {aioxlib-0.3.0 → aioxlib-0.4.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.4.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
|
|
@@ -52,6 +52,7 @@ The **root package** exposes the functional API and `get_display` only:
|
|
|
52
52
|
import asyncio
|
|
53
53
|
import aioxlib
|
|
54
54
|
|
|
55
|
+
|
|
55
56
|
async def main():
|
|
56
57
|
wnd = await aioxlib.create_window(640, 480, title="Hello from aioxlib")
|
|
57
58
|
await wnd.show()
|
|
@@ -60,6 +61,7 @@ async def main():
|
|
|
60
61
|
if wnd.is_delete_window(event):
|
|
61
62
|
break
|
|
62
63
|
|
|
64
|
+
|
|
63
65
|
asyncio.run(main())
|
|
64
66
|
```
|
|
65
67
|
|
|
@@ -69,6 +71,7 @@ asyncio.run(main())
|
|
|
69
71
|
import asyncio
|
|
70
72
|
import aioxlib
|
|
71
73
|
|
|
74
|
+
|
|
72
75
|
async def main():
|
|
73
76
|
display = await aioxlib.get_display()
|
|
74
77
|
async with display:
|
|
@@ -80,6 +83,7 @@ async def main():
|
|
|
80
83
|
if wnd.is_delete_window(event):
|
|
81
84
|
break
|
|
82
85
|
|
|
86
|
+
|
|
83
87
|
asyncio.run(main())
|
|
84
88
|
```
|
|
85
89
|
|
|
@@ -134,5 +138,5 @@ GPLv3 or later — see [LICENSE](LICENSE).
|
|
|
134
138
|
|
|
135
139
|
## Author
|
|
136
140
|
|
|
137
|
-
José Tiago Macara Coutinho
|
|
141
|
+
José Tiago Macara Coutinho
|
|
138
142
|
<https://codeberg.org/tiagocoutinho>
|
|
@@ -28,6 +28,7 @@ The **root package** exposes the functional API and `get_display` only:
|
|
|
28
28
|
import asyncio
|
|
29
29
|
import aioxlib
|
|
30
30
|
|
|
31
|
+
|
|
31
32
|
async def main():
|
|
32
33
|
wnd = await aioxlib.create_window(640, 480, title="Hello from aioxlib")
|
|
33
34
|
await wnd.show()
|
|
@@ -36,6 +37,7 @@ async def main():
|
|
|
36
37
|
if wnd.is_delete_window(event):
|
|
37
38
|
break
|
|
38
39
|
|
|
40
|
+
|
|
39
41
|
asyncio.run(main())
|
|
40
42
|
```
|
|
41
43
|
|
|
@@ -45,6 +47,7 @@ asyncio.run(main())
|
|
|
45
47
|
import asyncio
|
|
46
48
|
import aioxlib
|
|
47
49
|
|
|
50
|
+
|
|
48
51
|
async def main():
|
|
49
52
|
display = await aioxlib.get_display()
|
|
50
53
|
async with display:
|
|
@@ -56,6 +59,7 @@ async def main():
|
|
|
56
59
|
if wnd.is_delete_window(event):
|
|
57
60
|
break
|
|
58
61
|
|
|
62
|
+
|
|
59
63
|
asyncio.run(main())
|
|
60
64
|
```
|
|
61
65
|
|
|
@@ -110,5 +114,5 @@ GPLv3 or later — see [LICENSE](LICENSE).
|
|
|
110
114
|
|
|
111
115
|
## Author
|
|
112
116
|
|
|
113
|
-
José Tiago Macara Coutinho
|
|
117
|
+
José Tiago Macara Coutinho
|
|
114
118
|
<https://codeberg.org/tiagocoutinho>
|
|
@@ -772,7 +772,7 @@ class Display:
|
|
|
772
772
|
|
|
773
773
|
async def poly_fill_rectangles(self, drawable, gc, rectangles):
|
|
774
774
|
"""Poly fill rectangles."""
|
|
775
|
-
if isinstance(rectangles,
|
|
775
|
+
if isinstance(rectangles, bytes | bytearray):
|
|
776
776
|
payload = pack_poly_fill_raw_rectangles(drawable, gc, rectangles)
|
|
777
777
|
else:
|
|
778
778
|
payload = pack_poly_fill_rectangles(drawable, gc, rectangles)
|
|
@@ -784,7 +784,7 @@ class Display:
|
|
|
784
784
|
*arcs* is a sequence of ``(x, y, width, height, angle1, angle2)``
|
|
785
785
|
with angles in 1/64 degree units, or a pre-packed ``bytes`` LISTofARC.
|
|
786
786
|
"""
|
|
787
|
-
if isinstance(arcs,
|
|
787
|
+
if isinstance(arcs, bytes | bytearray):
|
|
788
788
|
payload = pack_poly_fill_raw_arcs(drawable, gc, arcs)
|
|
789
789
|
else:
|
|
790
790
|
payload = pack_poly_fill_arcs(drawable, gc, arcs)
|
|
@@ -871,42 +871,57 @@ class Display:
|
|
|
871
871
|
break
|
|
872
872
|
return error
|
|
873
873
|
|
|
874
|
+
async def _handle_buffer(self, buffer, current_decoder=None):
|
|
875
|
+
packet_type = buffer[0]
|
|
876
|
+
if packet_type == Status.Success:
|
|
877
|
+
if current_decoder is None:
|
|
878
|
+
current_decoder = await self.requests.get()
|
|
879
|
+
decode, future = current_decoder
|
|
880
|
+
if decode == unpack_setup:
|
|
881
|
+
size = 8 + 4 * int.from_bytes(buffer[6:8], BYTE_ORDER_TEXT)
|
|
882
|
+
else:
|
|
883
|
+
size = 32 + 4 * int.from_bytes(buffer[4:8], BYTE_ORDER_TEXT)
|
|
884
|
+
if len(buffer) < size:
|
|
885
|
+
return True, buffer, current_decoder
|
|
886
|
+
try:
|
|
887
|
+
reply, offset = decode(buffer, 0)
|
|
888
|
+
future.set_result(reply)
|
|
889
|
+
except Exception as error:
|
|
890
|
+
future.set_exception(error)
|
|
891
|
+
return False, buffer[offset:], None
|
|
892
|
+
elif packet_type == Status.Failed and not self.requests.empty():
|
|
893
|
+
decode, future = await self.requests.get()
|
|
894
|
+
if decode == unpack_setup:
|
|
895
|
+
# todo: check if buffer is complete
|
|
896
|
+
error, offset = unpack_setup_error(buffer)
|
|
897
|
+
future.set_exception(RuntimeError(error))
|
|
898
|
+
else:
|
|
899
|
+
if len(buffer) < 32:
|
|
900
|
+
return True, buffer, current_decoder
|
|
901
|
+
error, offset = unpack_error(buffer)
|
|
902
|
+
error = self._handle_error(error)
|
|
903
|
+
log.warning("ERROR: %s", error)
|
|
904
|
+
future.set_exception(X11Error(error))
|
|
905
|
+
return False, buffer[offset:], None
|
|
906
|
+
|
|
907
|
+
# An event
|
|
908
|
+
if len(buffer) < 32:
|
|
909
|
+
return True, buffer, current_decoder
|
|
910
|
+
event, offset = unpack_event(self._events, buffer)
|
|
911
|
+
for listener in self.listeners:
|
|
912
|
+
await listener.put(event)
|
|
913
|
+
return False, buffer[offset:], current_decoder
|
|
914
|
+
|
|
874
915
|
async def _loop(self):
|
|
875
|
-
buffer,
|
|
916
|
+
buffer, context = b"", None
|
|
876
917
|
while True:
|
|
877
|
-
if not (data := await self.read(
|
|
918
|
+
if not (data := await self.read(4096)):
|
|
878
919
|
log.info("Connection closed")
|
|
879
920
|
return
|
|
880
921
|
buffer += data
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
decoder = await self.requests.get()
|
|
885
|
-
decode, future = decoder
|
|
886
|
-
if decode == unpack_setup:
|
|
887
|
-
size = 8 + 4 * int.from_bytes(buffer[6:8], BYTE_ORDER_TEXT)
|
|
888
|
-
else:
|
|
889
|
-
size = 32 + 4 * int.from_bytes(buffer[4:8], BYTE_ORDER_TEXT)
|
|
890
|
-
if len(buffer) < size:
|
|
891
|
-
continue
|
|
892
|
-
reply, offset = decode(buffer, 0)
|
|
893
|
-
future.set_result(reply)
|
|
894
|
-
decoder = None
|
|
895
|
-
elif packet_type == Status.Failed and not self.requests.empty():
|
|
896
|
-
decode, future = await self.requests.get()
|
|
897
|
-
if decode == unpack_setup:
|
|
898
|
-
error, offset = unpack_setup_error(buffer)
|
|
899
|
-
future.set_exception(RuntimeError(error))
|
|
900
|
-
else:
|
|
901
|
-
error, offset = unpack_error(buffer)
|
|
902
|
-
error = self._handle_error(error)
|
|
903
|
-
log.warning("ERROR: %s", error)
|
|
904
|
-
future.set_exception(X11Error(error))
|
|
905
|
-
else:
|
|
906
|
-
event, offset = unpack_event(self._events, buffer)
|
|
907
|
-
for listener in self.listeners:
|
|
908
|
-
await listener.put(event)
|
|
909
|
-
buffer = buffer[offset:]
|
|
922
|
+
need_more = False
|
|
923
|
+
while not need_more and buffer:
|
|
924
|
+
need_more, buffer, context = await self._handle_buffer(buffer, context)
|
|
910
925
|
|
|
911
926
|
async def events(self):
|
|
912
927
|
"""Async iterator yielding event dicts from the server."""
|
|
@@ -933,7 +948,7 @@ def get_display_config(uri: str) -> dict:
|
|
|
933
948
|
display["protocol"] = protocol
|
|
934
949
|
display["port"] = int(display["port"])
|
|
935
950
|
display["uri"] = uri
|
|
936
|
-
display["screen"] = display["screen"] or 0
|
|
951
|
+
display["screen"] = int(display["screen"] or 0)
|
|
937
952
|
return display
|
|
938
953
|
|
|
939
954
|
|
|
@@ -613,7 +613,7 @@ def pack_glx_is_direct(opcode, context):
|
|
|
613
613
|
def unpack_glx_is_direct(data, offset=0):
|
|
614
614
|
"""Unpack a glx is direct reply or event from *data* starting at *offset*."""
|
|
615
615
|
result, offset = unpack_reply_head(data, offset)
|
|
616
|
-
result["is_direct"] = bool(
|
|
616
|
+
result["is_direct"] = bool(struct.unpack_from("B", data, offset)[0])
|
|
617
617
|
offset += 24
|
|
618
618
|
return result, offset
|
|
619
619
|
|
|
@@ -754,17 +754,22 @@ def pack_glx_get_fb_configs(opcode, screen):
|
|
|
754
754
|
|
|
755
755
|
def unpack_glx_get_fb_configs(data, offset=0):
|
|
756
756
|
"""Unpack a glx get fb configs reply or event from *data* starting at *offset*."""
|
|
757
|
+
start = offset
|
|
757
758
|
result, offset = unpack_reply_head(data, offset)
|
|
759
|
+
# Fixed fields at bytes 8..31 of the reply
|
|
758
760
|
n_cfgs, n_props = struct.unpack_from("II", data, offset)
|
|
759
|
-
offset +=
|
|
761
|
+
offset += struct.calcsize("II") + 16
|
|
760
762
|
total = n_cfgs * n_props
|
|
761
|
-
|
|
762
|
-
|
|
763
|
+
if total:
|
|
764
|
+
props = list(struct.unpack_from(f"{total}I", data, offset))
|
|
765
|
+
else:
|
|
766
|
+
props = []
|
|
763
767
|
configs = [props[i * n_props : (i + 1) * n_props] for i in range(n_cfgs)]
|
|
764
768
|
result["num_fb_configs"] = n_cfgs
|
|
765
769
|
result["num_properties"] = n_props
|
|
766
770
|
result["fb_configs"] = configs
|
|
767
|
-
|
|
771
|
+
# Always consume the full reply so the connection buffer stays aligned
|
|
772
|
+
return result, start + 32 + 4 * result["length"]
|
|
768
773
|
|
|
769
774
|
|
|
770
775
|
def pack_glx_create_new_context(
|
|
@@ -793,32 +798,51 @@ def pack_glx_create_new_context(
|
|
|
793
798
|
|
|
794
799
|
|
|
795
800
|
def pack_glx_make_context_current(opcode, drawable, read_drawable, context, old_context_tag=0):
|
|
796
|
-
"""Pack a wire-protocol glx make context current request into ``bytes``.
|
|
801
|
+
"""Pack a wire-protocol glx make context current request into ``bytes``.
|
|
802
|
+
|
|
803
|
+
Wire order (glxproto.h)::
|
|
804
|
+
|
|
805
|
+
oldContextTag, drawable, readdrawable, context
|
|
806
|
+
"""
|
|
797
807
|
return struct.pack(
|
|
798
808
|
"BBHIIII",
|
|
799
809
|
opcode,
|
|
800
810
|
GLXCommand.MakeContextCurrent,
|
|
801
811
|
5,
|
|
812
|
+
int(old_context_tag),
|
|
802
813
|
int(drawable),
|
|
803
814
|
int(read_drawable),
|
|
804
815
|
int(context),
|
|
805
|
-
int(old_context_tag),
|
|
806
816
|
)
|
|
807
817
|
|
|
808
818
|
|
|
809
|
-
def pack_glx_create_pbuffer(
|
|
810
|
-
|
|
819
|
+
def pack_glx_create_pbuffer(
|
|
820
|
+
opcode,
|
|
821
|
+
pbuffer,
|
|
822
|
+
fbconfig,
|
|
823
|
+
screen=0,
|
|
824
|
+
attrs: list[tuple[int, int]] | None = None,
|
|
825
|
+
):
|
|
826
|
+
"""Pack a wire-protocol glx create pbuffer request into ``bytes``.
|
|
827
|
+
|
|
828
|
+
Wire order (xcb)::
|
|
829
|
+
|
|
830
|
+
screen, fbconfig, pbuffer, num_attribs, attribs[num_attribs*2]
|
|
831
|
+
|
|
832
|
+
Fixed header ``BBHIIII`` is 5 units plus 2 per attribute pair.
|
|
833
|
+
"""
|
|
811
834
|
attrs = attrs or []
|
|
812
835
|
n = len(attrs)
|
|
813
|
-
length =
|
|
836
|
+
length = 5 + 2 * n
|
|
814
837
|
parts = [
|
|
815
838
|
struct.pack(
|
|
816
|
-
"
|
|
839
|
+
"BBHIIII",
|
|
817
840
|
opcode,
|
|
818
841
|
GLXCommand.CreatePbuffer,
|
|
819
842
|
length,
|
|
820
|
-
int(
|
|
843
|
+
int(screen),
|
|
821
844
|
int(fbconfig),
|
|
845
|
+
int(pbuffer),
|
|
822
846
|
n,
|
|
823
847
|
)
|
|
824
848
|
]
|
|
@@ -832,20 +856,36 @@ def pack_glx_destroy_pbuffer(opcode, pbuffer):
|
|
|
832
856
|
return struct.pack("BBHI", opcode, GLXCommand.DestroyPbuffer, 2, int(pbuffer))
|
|
833
857
|
|
|
834
858
|
|
|
835
|
-
def pack_glx_create_window(
|
|
836
|
-
|
|
859
|
+
def pack_glx_create_window(
|
|
860
|
+
opcode,
|
|
861
|
+
glx_window,
|
|
862
|
+
fbconfig,
|
|
863
|
+
x_window,
|
|
864
|
+
screen=0,
|
|
865
|
+
attrs: list[tuple[int, int]] | None = None,
|
|
866
|
+
):
|
|
867
|
+
"""Pack a wire-protocol glx create window request into ``bytes``.
|
|
868
|
+
|
|
869
|
+
Wire order (GLX 1.3 / xcb)::
|
|
870
|
+
|
|
871
|
+
screen, fbconfig, x_window, glx_window, num_attribs, attribs[num_attribs*2]
|
|
872
|
+
|
|
873
|
+
Request length is in 4-byte units: fixed header ``BBHIIIII`` is 6 units
|
|
874
|
+
plus 2 units per attribute/value pair.
|
|
875
|
+
"""
|
|
837
876
|
attrs = attrs or []
|
|
838
877
|
n = len(attrs)
|
|
839
|
-
length =
|
|
878
|
+
length = 6 + 2 * n
|
|
840
879
|
parts = [
|
|
841
880
|
struct.pack(
|
|
842
|
-
"
|
|
881
|
+
"=BBHIIIII",
|
|
843
882
|
opcode,
|
|
844
883
|
GLXCommand.CreateWindow,
|
|
845
884
|
length,
|
|
846
|
-
int(
|
|
885
|
+
int(screen),
|
|
847
886
|
int(fbconfig),
|
|
848
887
|
int(x_window),
|
|
888
|
+
int(glx_window),
|
|
849
889
|
n,
|
|
850
890
|
)
|
|
851
891
|
]
|
|
@@ -1395,22 +1435,56 @@ class GLX(Extension):
|
|
|
1395
1435
|
)
|
|
1396
1436
|
return context
|
|
1397
1437
|
|
|
1398
|
-
async def create_window(self, fbconfig, x_window, attrs=None, window=None):
|
|
1399
|
-
"""Create window.
|
|
1438
|
+
async def create_window(self, fbconfig, x_window, screen=None, attrs=None, window=None):
|
|
1439
|
+
"""Create a GLX window wrapping an X11 window for the given FBConfig.
|
|
1440
|
+
|
|
1441
|
+
Parameters
|
|
1442
|
+
----------
|
|
1443
|
+
fbconfig:
|
|
1444
|
+
FBConfig id (from :meth:`get_fb_configs`).
|
|
1445
|
+
x_window:
|
|
1446
|
+
Existing X11 window XID (must use a visual compatible with *fbconfig*).
|
|
1447
|
+
screen:
|
|
1448
|
+
Screen number (default: display default screen).
|
|
1449
|
+
attrs:
|
|
1450
|
+
Optional list of ``(attribute, value)`` pairs.
|
|
1451
|
+
window:
|
|
1452
|
+
Optional GLX window id; allocated if omitted (must differ from *x_window*).
|
|
1453
|
+
"""
|
|
1454
|
+
x_window = int(x_window)
|
|
1455
|
+
fbconfig = int(fbconfig)
|
|
1456
|
+
if screen is None:
|
|
1457
|
+
screen = self.display.config.get("screen", 0)
|
|
1458
|
+
screen = int(screen)
|
|
1400
1459
|
if window is None:
|
|
1401
1460
|
window = self.display.resources.allocate()
|
|
1402
|
-
|
|
1461
|
+
window = int(window)
|
|
1462
|
+
# GLX window XID must be a fresh client ID, not the X11 window
|
|
1463
|
+
if window == x_window or window == 0:
|
|
1464
|
+
window = int(self.display.resources.allocate())
|
|
1465
|
+
self.display.write(
|
|
1466
|
+
pack_glx_create_window(
|
|
1467
|
+
self.code,
|
|
1468
|
+
window,
|
|
1469
|
+
fbconfig,
|
|
1470
|
+
x_window,
|
|
1471
|
+
screen=screen,
|
|
1472
|
+
attrs=attrs,
|
|
1473
|
+
)
|
|
1474
|
+
)
|
|
1403
1475
|
return window
|
|
1404
1476
|
|
|
1405
1477
|
async def destroy_window(self, window):
|
|
1406
1478
|
"""Destroy window."""
|
|
1407
1479
|
self.display.write(pack_glx_destroy_window(self.code, window))
|
|
1408
1480
|
|
|
1409
|
-
async def create_pbuffer(self, fbconfig, attrs=None, pbuffer=None):
|
|
1481
|
+
async def create_pbuffer(self, fbconfig, attrs=None, pbuffer=None, screen=None):
|
|
1410
1482
|
"""Create pbuffer."""
|
|
1411
1483
|
if pbuffer is None:
|
|
1412
1484
|
pbuffer = self.display.resources.allocate()
|
|
1413
|
-
|
|
1485
|
+
if screen is None:
|
|
1486
|
+
screen = self.display.config.get("screen", 0)
|
|
1487
|
+
self.display.write(pack_glx_create_pbuffer(self.code, pbuffer, fbconfig, screen=screen, attrs=attrs))
|
|
1414
1488
|
return pbuffer
|
|
1415
1489
|
|
|
1416
1490
|
async def destroy_pbuffer(self, pbuffer):
|
|
@@ -643,14 +643,14 @@ def pack_clear_area(wnd, x, y, w, h, exposure=False):
|
|
|
643
643
|
|
|
644
644
|
def pack_change_property(wid, property, property_type, format, data, mode):
|
|
645
645
|
"""Pack a wire-protocol change property request into ``bytes``."""
|
|
646
|
-
if not isinstance(data,
|
|
646
|
+
if not isinstance(data, bytes | bytearray):
|
|
647
647
|
format, data = encode_property_value(property_type, data, format)
|
|
648
648
|
elif format is None:
|
|
649
649
|
format = 8
|
|
650
650
|
|
|
651
651
|
n = len(data)
|
|
652
652
|
size = format // 8
|
|
653
|
-
if isinstance(data,
|
|
653
|
+
if isinstance(data, bytes | bytearray):
|
|
654
654
|
if n % size:
|
|
655
655
|
n -= n % size
|
|
656
656
|
raw = data[:n]
|
|
@@ -726,7 +726,7 @@ def encode_property_value(property_type, data, format=None):
|
|
|
726
726
|
* ``list``/``tuple`` of ``str`` — NUL-separated STRING
|
|
727
727
|
* ``list``/``tuple`` of ``int`` — format 16 or 32 array
|
|
728
728
|
"""
|
|
729
|
-
if isinstance(data,
|
|
729
|
+
if isinstance(data, bytes | bytearray):
|
|
730
730
|
return (format if format is not None else 8), bytes(data)
|
|
731
731
|
|
|
732
732
|
if isinstance(data, str):
|
|
@@ -735,7 +735,7 @@ def encode_property_value(property_type, data, format=None):
|
|
|
735
735
|
if isinstance(data, int):
|
|
736
736
|
return (format if format is not None else 32), [data]
|
|
737
737
|
|
|
738
|
-
if isinstance(data,
|
|
738
|
+
if isinstance(data, list | tuple):
|
|
739
739
|
if not data:
|
|
740
740
|
return (format if format is not None else 32), []
|
|
741
741
|
if isinstance(data[0], str):
|
|
@@ -813,13 +813,15 @@ def pack_list_extensions():
|
|
|
813
813
|
def unpack_list_strings(data, n, offset):
|
|
814
814
|
"""Unpack a list strings reply or event from *data* starting at *offset*."""
|
|
815
815
|
result = []
|
|
816
|
+
total = 0
|
|
816
817
|
for _ in range(n):
|
|
817
818
|
(size,) = struct.unpack_from("B", data, offset)
|
|
818
819
|
offset += 1
|
|
819
820
|
(text,) = struct.unpack_from(f"{size}s", data, offset)
|
|
820
821
|
offset += size
|
|
822
|
+
total += 1 + size
|
|
821
823
|
result.append(text.decode())
|
|
822
|
-
return result, offset
|
|
824
|
+
return result, offset + pad(total)
|
|
823
825
|
|
|
824
826
|
|
|
825
827
|
def unpack_list_extensions(data: bytes, offset: int = 0):
|
|
@@ -829,7 +831,7 @@ def unpack_list_extensions(data: bytes, offset: int = 0):
|
|
|
829
831
|
n = result["n"]
|
|
830
832
|
offset += 24
|
|
831
833
|
result["extensions"], offset = unpack_list_strings(data, n, offset)
|
|
832
|
-
return result, offset
|
|
834
|
+
return result, offset
|
|
833
835
|
|
|
834
836
|
|
|
835
837
|
def pack_query_extension(name) -> bytes:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aioxlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -52,6 +52,7 @@ The **root package** exposes the functional API and `get_display` only:
|
|
|
52
52
|
import asyncio
|
|
53
53
|
import aioxlib
|
|
54
54
|
|
|
55
|
+
|
|
55
56
|
async def main():
|
|
56
57
|
wnd = await aioxlib.create_window(640, 480, title="Hello from aioxlib")
|
|
57
58
|
await wnd.show()
|
|
@@ -60,6 +61,7 @@ async def main():
|
|
|
60
61
|
if wnd.is_delete_window(event):
|
|
61
62
|
break
|
|
62
63
|
|
|
64
|
+
|
|
63
65
|
asyncio.run(main())
|
|
64
66
|
```
|
|
65
67
|
|
|
@@ -69,6 +71,7 @@ asyncio.run(main())
|
|
|
69
71
|
import asyncio
|
|
70
72
|
import aioxlib
|
|
71
73
|
|
|
74
|
+
|
|
72
75
|
async def main():
|
|
73
76
|
display = await aioxlib.get_display()
|
|
74
77
|
async with display:
|
|
@@ -80,6 +83,7 @@ async def main():
|
|
|
80
83
|
if wnd.is_delete_window(event):
|
|
81
84
|
break
|
|
82
85
|
|
|
86
|
+
|
|
83
87
|
asyncio.run(main())
|
|
84
88
|
```
|
|
85
89
|
|
|
@@ -134,5 +138,5 @@ GPLv3 or later — see [LICENSE](LICENSE).
|
|
|
134
138
|
|
|
135
139
|
## Author
|
|
136
140
|
|
|
137
|
-
José Tiago Macara Coutinho
|
|
141
|
+
José Tiago Macara Coutinho
|
|
138
142
|
<https://codeberg.org/tiagocoutinho>
|
|
@@ -120,13 +120,13 @@ class TestGLXPack:
|
|
|
120
120
|
def test_create_new_context_and_pbuffer(self):
|
|
121
121
|
p = pack_glx_create_new_context(self.OPCODE, 0x10, 0x50, 0, 0x8014, 0, True)
|
|
122
122
|
assert p[1] == GLXCommand.CreateNewContext
|
|
123
|
-
p = pack_glx_create_pbuffer(self.OPCODE, 0x60, 0x50, [(0x801D, 64), (0x801E, 64)])
|
|
123
|
+
p = pack_glx_create_pbuffer(self.OPCODE, 0x60, 0x50, 0, [(0x801D, 64), (0x801E, 64)])
|
|
124
124
|
assert p[1] == GLXCommand.CreatePbuffer
|
|
125
125
|
p = pack_glx_destroy_pbuffer(self.OPCODE, 0x60)
|
|
126
126
|
assert p[1] == GLXCommand.DestroyPbuffer
|
|
127
127
|
|
|
128
128
|
def test_window_and_attribs_arb(self):
|
|
129
|
-
p = pack_glx_create_window(self.OPCODE, 0x70, 0x50, 0x100, None)
|
|
129
|
+
p = pack_glx_create_window(self.OPCODE, 0x70, 0x50, 0x100, 0, None)
|
|
130
130
|
assert p[1] == GLXCommand.CreateWindow
|
|
131
131
|
p = pack_glx_destroy_window(self.OPCODE, 0x70)
|
|
132
132
|
assert p[1] == GLXCommand.DestroyWindow
|
|
@@ -152,7 +152,7 @@ class TestGLXUnpack:
|
|
|
152
152
|
|
|
153
153
|
def test_is_direct_reply(self):
|
|
154
154
|
# n field in reply head is the is_direct flag
|
|
155
|
-
data = struct.pack("
|
|
155
|
+
data = struct.pack("BBHIB", 1, 1, 1, 0, 1) + b"\0" * 23
|
|
156
156
|
r, _ = unpack_glx_is_direct(data)
|
|
157
157
|
assert r["is_direct"] is True
|
|
158
158
|
|
|
@@ -235,7 +235,7 @@ class TestGLXClass:
|
|
|
235
235
|
@pytest.mark.asyncio
|
|
236
236
|
async def test_is_direct_and_swap(self, glx, display):
|
|
237
237
|
async def write_read(payload, callback):
|
|
238
|
-
data = struct.pack("
|
|
238
|
+
data = struct.pack("BBHIB", 1, 1, 1, 0, 1) + b"\0" * 23
|
|
239
239
|
return callback(data, 0)[0]
|
|
240
240
|
|
|
241
241
|
display.write_read = write_read
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|