aioxlib 0.7.1__tar.gz → 0.8.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.7.1 → aioxlib-0.8.0}/PKG-INFO +72 -30
- aioxlib-0.8.0/README.md +162 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/__init__.py +1 -1
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/constants.py +36 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/display.py +55 -2
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/protocol.py +106 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib.egg-info/PKG-INFO +72 -30
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_display.py +1 -1
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_protocol.py +97 -0
- aioxlib-0.7.1/README.md +0 -120
- {aioxlib-0.7.1 → aioxlib-0.8.0}/LICENSE +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/_extensions.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/api.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/authority.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/bigreq.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/connection.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/dbe.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/dri3.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/glx.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/present.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/randr.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/render.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/shm.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib/widgets.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib.egg-info/SOURCES.txt +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib.egg-info/dependency_links.txt +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/aioxlib.egg-info/top_level.txt +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/pyproject.toml +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/setup.cfg +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_api.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_authority.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_bigreq.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_connection.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_constants.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_dbe.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_dri3.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_examples.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_extensions.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_glx.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_present.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_randr.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_render.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_shm.py +0 -0
- {aioxlib-0.7.1 → aioxlib-0.8.0}/tests/test_widgets.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aioxlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.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
|
|
@@ -31,18 +31,42 @@ Dynamic: license-file
|
|
|
31
31
|
[](https://pypi.org/project/aioxlib/)
|
|
32
32
|
[](https://pypi.org/project/aioxlib/)
|
|
33
33
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
34
|
+
[](https://aioxlib.readthedocs.io)
|
|
34
35
|
|
|
35
|
-
`aioxlib` is a pure-Python
|
|
36
|
-
|
|
36
|
+
`aioxlib` is a **pure-Python**, **asyncio-native** client for the X11 wire protocol.
|
|
37
|
+
Open displays, create windows, draw with GCs and the RENDER extension, and stream
|
|
38
|
+
events — without blocking the event loop and without linking to libX11 or xcb.
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="docs/images/game_of_life.gif" style="height: 300px;" alt="Conway's Game of Life on X11 via aioxlib"/>
|
|
42
|
+
|
|
43
|
+
<img src="docs/images/3d_cube.gif" style="height: 300px;" alt="Rotating 3D wireframe via aioxlib"/>
|
|
44
|
+
</p>
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
- Local: `pip install --group docs && mkdocs serve`
|
|
46
|
+
<p align="center"><em>Examples shipped with the library: Game of Life · 3D wireframe</em></p>
|
|
42
47
|
|
|
43
|
-
##
|
|
48
|
+
## Why aioxlib?
|
|
49
|
+
|
|
50
|
+
| | **aioxlib** | python-xlib | xcffib / xpyb |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| Language | Pure Python | Pure Python | C (libxcb) + Python |
|
|
53
|
+
| Async | **asyncio first** | Blocking / threads | Blocking |
|
|
54
|
+
| Dependencies | None at runtime | None | libxcb |
|
|
55
|
+
| Protocol access | Pack/unpack helpers exposed | High-level only | Low-level |
|
|
56
|
+
| Extensions | RENDER, MIT-SHM, DBE, GLX, … | Many | Many |
|
|
57
|
+
|
|
58
|
+
Inspired by [linuxpy](https://github.com/tiagocoutinho/linuxpy) (same author):
|
|
59
|
+
a clean high-level API when you want it, full protocol detail when you need it.
|
|
60
|
+
|
|
61
|
+
## Requirements
|
|
62
|
+
|
|
63
|
+
- **Python ≥ 3.12**
|
|
64
|
+
- An X server (local or remote) and network/socket access to it
|
|
65
|
+
(`$DISPLAY` or an explicit URI)
|
|
44
66
|
|
|
45
|
-
|
|
67
|
+
No third-party Python packages are required at runtime.
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
46
70
|
|
|
47
71
|
```bash
|
|
48
72
|
pip install aioxlib
|
|
@@ -50,7 +74,7 @@ pip install aioxlib
|
|
|
50
74
|
|
|
51
75
|
## Quick start
|
|
52
76
|
|
|
53
|
-
|
|
77
|
+
### Functional API (simplest)
|
|
54
78
|
|
|
55
79
|
```python
|
|
56
80
|
import asyncio
|
|
@@ -91,19 +115,49 @@ async def main():
|
|
|
91
115
|
asyncio.run(main())
|
|
92
116
|
```
|
|
93
117
|
|
|
118
|
+
## Features
|
|
119
|
+
|
|
120
|
+
- **Windows & drawing** — create/map/configure windows, GCs, polylines, rectangles, arcs, text, images
|
|
121
|
+
- **Events** — non-blocking `async for event in display.events()` stream
|
|
122
|
+
- **Properties & atoms** — `WM_NAME`, protocols, custom properties
|
|
123
|
+
- **Extensions** — BIG-REQUESTS, RENDER, MIT-SHM, DBE, GLX, RANDR, DRI3, Present
|
|
124
|
+
- **Pipeline** — batch requests with `async with display.pipeline(): …`
|
|
125
|
+
- **Protocol transparent** — opcodes, pack/unpack helpers stay accessible
|
|
126
|
+
|
|
127
|
+
## Examples
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# clone the repo, then:
|
|
131
|
+
python examples/basic.py
|
|
132
|
+
python examples/game_of_life.py # Conway's Life (numpy)
|
|
133
|
+
python examples/3d.py # rotating 3D mesh
|
|
134
|
+
python examples/video_shm_dbe.py # shared memory + double buffering
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Example | What it shows |
|
|
138
|
+
|---------|----------------|
|
|
139
|
+
| `basic.py` | Window + delete protocol |
|
|
140
|
+
| `game_of_life.py` | Animated cellular automaton |
|
|
141
|
+
| `3d.py` | Perspective projection & wireframe |
|
|
142
|
+
| `render.py` / `tristrip.py` | RENDER extension |
|
|
143
|
+
| `shm.py` / `video_shm*.py` | MIT-SHM image transfer |
|
|
144
|
+
| `cube_dbe.py` | Double buffering (DBE) |
|
|
145
|
+
| `keyboard.py` | Key events |
|
|
146
|
+
|
|
94
147
|
## Package layout
|
|
95
148
|
|
|
96
149
|
| Module | Contents |
|
|
97
150
|
|--------|----------|
|
|
98
|
-
| **`aioxlib`** (root) |
|
|
151
|
+
| **`aioxlib`** (root) | Functional API + `get_display` + common constants |
|
|
99
152
|
| `aioxlib.constants` | X11 constants and enumerations |
|
|
100
|
-
| `aioxlib.protocol` |
|
|
153
|
+
| `aioxlib.protocol` | Pack/unpack helpers |
|
|
101
154
|
| `aioxlib.connection` | Socket connection, Xauthority |
|
|
102
|
-
| `aioxlib.
|
|
103
|
-
| `aioxlib.display` (Window, Screen, GC, …) | Window, Screen, GC |
|
|
104
|
-
| `aioxlib.display` | Display, Pipeline |
|
|
155
|
+
| `aioxlib.display` | `Display`, `Screen`, `Window`, `GC`, `Pipeline` |
|
|
105
156
|
| `aioxlib.render` / `shm` / `dbe` / … | Extensions |
|
|
106
157
|
|
|
158
|
+
Classes such as `Display`, `Window`, and `EventType` are imported from their
|
|
159
|
+
modules (or from the root where re-exported).
|
|
160
|
+
|
|
107
161
|
### Root functional API (selection)
|
|
108
162
|
|
|
109
163
|
| Function | Role |
|
|
@@ -114,28 +168,16 @@ asyncio.run(main())
|
|
|
114
168
|
| `flush`, `query_extension`, `get_atom`, … | Display operations |
|
|
115
169
|
| `close_default_display` | Tear down default connection |
|
|
116
170
|
|
|
117
|
-
Classes such as `Display`, `Window`, and `EventType` are **not** re-exported
|
|
118
|
-
from the root; import them from their modules.
|
|
119
|
-
|
|
120
171
|
## Documentation
|
|
121
172
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
mkdocs serve
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Examples
|
|
173
|
+
- Online: [aioxlib.readthedocs.io](https://aioxlib.readthedocs.io)
|
|
174
|
+
- Local:
|
|
128
175
|
|
|
129
176
|
```bash
|
|
130
|
-
python
|
|
131
|
-
|
|
177
|
+
pip install --group docs # or: pip install mkdocs mkdocs-material 'mkdocstrings[python]'
|
|
178
|
+
mkdocs serve
|
|
132
179
|
```
|
|
133
180
|
|
|
134
|
-
## Requirements
|
|
135
|
-
|
|
136
|
-
- Python ≥ 3.12
|
|
137
|
-
- An X11 server and `$DISPLAY` (or an explicit URI)
|
|
138
|
-
|
|
139
181
|
## License
|
|
140
182
|
|
|
141
183
|
GPLv3 or later — see [LICENSE](LICENSE).
|
aioxlib-0.8.0/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# aioxlib
|
|
2
|
+
|
|
3
|
+
**Human-friendly asyncio interface to the X11 protocol**
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/aioxlib/)
|
|
6
|
+
[](https://pypi.org/project/aioxlib/)
|
|
7
|
+
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
8
|
+
[](https://aioxlib.readthedocs.io)
|
|
9
|
+
|
|
10
|
+
`aioxlib` is a **pure-Python**, **asyncio-native** client for the X11 wire protocol.
|
|
11
|
+
Open displays, create windows, draw with GCs and the RENDER extension, and stream
|
|
12
|
+
events — without blocking the event loop and without linking to libX11 or xcb.
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="docs/images/game_of_life.gif" style="height: 300px;" alt="Conway's Game of Life on X11 via aioxlib"/>
|
|
16
|
+
|
|
17
|
+
<img src="docs/images/3d_cube.gif" style="height: 300px;" alt="Rotating 3D wireframe via aioxlib"/>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center"><em>Examples shipped with the library: Game of Life · 3D wireframe</em></p>
|
|
21
|
+
|
|
22
|
+
## Why aioxlib?
|
|
23
|
+
|
|
24
|
+
| | **aioxlib** | python-xlib | xcffib / xpyb |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| Language | Pure Python | Pure Python | C (libxcb) + Python |
|
|
27
|
+
| Async | **asyncio first** | Blocking / threads | Blocking |
|
|
28
|
+
| Dependencies | None at runtime | None | libxcb |
|
|
29
|
+
| Protocol access | Pack/unpack helpers exposed | High-level only | Low-level |
|
|
30
|
+
| Extensions | RENDER, MIT-SHM, DBE, GLX, … | Many | Many |
|
|
31
|
+
|
|
32
|
+
Inspired by [linuxpy](https://github.com/tiagocoutinho/linuxpy) (same author):
|
|
33
|
+
a clean high-level API when you want it, full protocol detail when you need it.
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- **Python ≥ 3.12**
|
|
38
|
+
- An X server (local or remote) and network/socket access to it
|
|
39
|
+
(`$DISPLAY` or an explicit URI)
|
|
40
|
+
|
|
41
|
+
No third-party Python packages are required at runtime.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install aioxlib
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
50
|
+
|
|
51
|
+
### Functional API (simplest)
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import asyncio
|
|
55
|
+
import aioxlib
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
async def main():
|
|
59
|
+
wnd = await aioxlib.create_window(640, 480, title="Hello from aioxlib")
|
|
60
|
+
await wnd.show()
|
|
61
|
+
|
|
62
|
+
async for event in aioxlib.events():
|
|
63
|
+
if wnd.is_delete_window(event):
|
|
64
|
+
break
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
asyncio.run(main())
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Explicit display (object API)
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import asyncio
|
|
74
|
+
import aioxlib
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def main():
|
|
78
|
+
display = await aioxlib.get_display()
|
|
79
|
+
async with display:
|
|
80
|
+
screen = display.default_screen()
|
|
81
|
+
wnd = await screen.create_window(640, 480, title="Hello from aioxlib")
|
|
82
|
+
await wnd.show()
|
|
83
|
+
|
|
84
|
+
async for event in display.events():
|
|
85
|
+
if wnd.is_delete_window(event):
|
|
86
|
+
break
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
asyncio.run(main())
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Features
|
|
93
|
+
|
|
94
|
+
- **Windows & drawing** — create/map/configure windows, GCs, polylines, rectangles, arcs, text, images
|
|
95
|
+
- **Events** — non-blocking `async for event in display.events()` stream
|
|
96
|
+
- **Properties & atoms** — `WM_NAME`, protocols, custom properties
|
|
97
|
+
- **Extensions** — BIG-REQUESTS, RENDER, MIT-SHM, DBE, GLX, RANDR, DRI3, Present
|
|
98
|
+
- **Pipeline** — batch requests with `async with display.pipeline(): …`
|
|
99
|
+
- **Protocol transparent** — opcodes, pack/unpack helpers stay accessible
|
|
100
|
+
|
|
101
|
+
## Examples
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# clone the repo, then:
|
|
105
|
+
python examples/basic.py
|
|
106
|
+
python examples/game_of_life.py # Conway's Life (numpy)
|
|
107
|
+
python examples/3d.py # rotating 3D mesh
|
|
108
|
+
python examples/video_shm_dbe.py # shared memory + double buffering
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| Example | What it shows |
|
|
112
|
+
|---------|----------------|
|
|
113
|
+
| `basic.py` | Window + delete protocol |
|
|
114
|
+
| `game_of_life.py` | Animated cellular automaton |
|
|
115
|
+
| `3d.py` | Perspective projection & wireframe |
|
|
116
|
+
| `render.py` / `tristrip.py` | RENDER extension |
|
|
117
|
+
| `shm.py` / `video_shm*.py` | MIT-SHM image transfer |
|
|
118
|
+
| `cube_dbe.py` | Double buffering (DBE) |
|
|
119
|
+
| `keyboard.py` | Key events |
|
|
120
|
+
|
|
121
|
+
## Package layout
|
|
122
|
+
|
|
123
|
+
| Module | Contents |
|
|
124
|
+
|--------|----------|
|
|
125
|
+
| **`aioxlib`** (root) | Functional API + `get_display` + common constants |
|
|
126
|
+
| `aioxlib.constants` | X11 constants and enumerations |
|
|
127
|
+
| `aioxlib.protocol` | Pack/unpack helpers |
|
|
128
|
+
| `aioxlib.connection` | Socket connection, Xauthority |
|
|
129
|
+
| `aioxlib.display` | `Display`, `Screen`, `Window`, `GC`, `Pipeline` |
|
|
130
|
+
| `aioxlib.render` / `shm` / `dbe` / … | Extensions |
|
|
131
|
+
|
|
132
|
+
Classes such as `Display`, `Window`, and `EventType` are imported from their
|
|
133
|
+
modules (or from the root where re-exported).
|
|
134
|
+
|
|
135
|
+
### Root functional API (selection)
|
|
136
|
+
|
|
137
|
+
| Function | Role |
|
|
138
|
+
|----------|------|
|
|
139
|
+
| `get_display` / `get_default_display` | Open connection |
|
|
140
|
+
| `create_window`, `map_window`, … | Windows |
|
|
141
|
+
| `events()`, `pipeline()` | Event stream / batched writes |
|
|
142
|
+
| `flush`, `query_extension`, `get_atom`, … | Display operations |
|
|
143
|
+
| `close_default_display` | Tear down default connection |
|
|
144
|
+
|
|
145
|
+
## Documentation
|
|
146
|
+
|
|
147
|
+
- Online: [aioxlib.readthedocs.io](https://aioxlib.readthedocs.io)
|
|
148
|
+
- Local:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pip install --group docs # or: pip install mkdocs mkdocs-material 'mkdocstrings[python]'
|
|
152
|
+
mkdocs serve
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
GPLv3 or later — see [LICENSE](LICENSE).
|
|
158
|
+
|
|
159
|
+
## Author
|
|
160
|
+
|
|
161
|
+
José Tiago Macara Coutinho
|
|
162
|
+
<https://codeberg.org/tiagocoutinho>
|
|
@@ -925,6 +925,36 @@ class WinGravity(enum.IntEnum):
|
|
|
925
925
|
Static = 10
|
|
926
926
|
|
|
927
927
|
|
|
928
|
+
# Number of 32-bit fields in the ICCCM / Xlib XWMHints structure
|
|
929
|
+
XWM_HINTS_LEN = 9
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
class WMHintsFlag(enum.IntFlag):
|
|
933
|
+
"""Bits for the ``flags`` field — which of the following fields are valid.
|
|
934
|
+
|
|
935
|
+
Values match the ICCCM / Xlib ``XWMHints`` definition.
|
|
936
|
+
"""
|
|
937
|
+
|
|
938
|
+
InputHint = 1 << 0
|
|
939
|
+
StateHint = 1 << 1
|
|
940
|
+
IconPixmapHint = 1 << 2
|
|
941
|
+
IconWindowHint = 1 << 3
|
|
942
|
+
IconPositionHint = 1 << 4
|
|
943
|
+
IconMaskHint = 1 << 5
|
|
944
|
+
WindowGroupHint = 1 << 6
|
|
945
|
+
# bit 7 was WithdrawnHint (obsolete)
|
|
946
|
+
UrgencyHint = 1 << 8
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
class InitialState(enum.IntEnum):
|
|
950
|
+
"""Values for the ``initial_state`` field."""
|
|
951
|
+
|
|
952
|
+
Withdrawn = 0
|
|
953
|
+
Normal = 1
|
|
954
|
+
# 2 was ZoomState (obsolete)
|
|
955
|
+
Iconic = 3
|
|
956
|
+
|
|
957
|
+
|
|
928
958
|
LSBFirst = 0
|
|
929
959
|
|
|
930
960
|
MSBFirst = 1
|
|
@@ -1148,6 +1178,12 @@ __all__ = [
|
|
|
1148
1178
|
"MotifFunc",
|
|
1149
1179
|
"MotifDecor",
|
|
1150
1180
|
"MotifInputMode",
|
|
1181
|
+
"XSIZE_HINTS_LEN",
|
|
1182
|
+
"SizeHintsFlag",
|
|
1183
|
+
"WinGravity",
|
|
1184
|
+
"XWM_HINTS_LEN",
|
|
1185
|
+
"WMHintsFlag",
|
|
1186
|
+
"InitialState",
|
|
1151
1187
|
"LSBFirst",
|
|
1152
1188
|
"MSBFirst",
|
|
1153
1189
|
"GenericEventCode",
|
|
@@ -32,6 +32,7 @@ from .constants import (
|
|
|
32
32
|
ErrorCode,
|
|
33
33
|
EventType,
|
|
34
34
|
ImageFormat,
|
|
35
|
+
InitialState,
|
|
35
36
|
PropMode,
|
|
36
37
|
StackMode,
|
|
37
38
|
Status,
|
|
@@ -42,6 +43,7 @@ from .protocol import (
|
|
|
42
43
|
build_font,
|
|
43
44
|
build_motif_wm_hints,
|
|
44
45
|
build_size_hints,
|
|
46
|
+
build_wm_hints,
|
|
45
47
|
pack_change_property,
|
|
46
48
|
pack_clear_area,
|
|
47
49
|
pack_configure_window,
|
|
@@ -338,7 +340,7 @@ class Window(Drawable):
|
|
|
338
340
|
status=status,
|
|
339
341
|
)
|
|
340
342
|
atom = await self.display.get_atom(MOTIF_WM_HINTS_ATOM)
|
|
341
|
-
await self.change_property(atom, atom, 32,
|
|
343
|
+
await self.change_property(atom, atom, 32, data)
|
|
342
344
|
|
|
343
345
|
async def set_size_hints(
|
|
344
346
|
self,
|
|
@@ -409,7 +411,58 @@ class Window(Drawable):
|
|
|
409
411
|
Atom.WM_NORMAL_HINTS,
|
|
410
412
|
Atom.WM_SIZE_HINTS,
|
|
411
413
|
32,
|
|
412
|
-
|
|
414
|
+
data,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
async def set_wm_hints(
|
|
418
|
+
window: Window,
|
|
419
|
+
*,
|
|
420
|
+
input: bool | None = None,
|
|
421
|
+
initial_state: InitialState | int | None = None,
|
|
422
|
+
icon_pixmap: int | None = None,
|
|
423
|
+
icon_window: int | None = None,
|
|
424
|
+
icon_x: int | None = None,
|
|
425
|
+
icon_y: int | None = None,
|
|
426
|
+
icon_mask: int | None = None,
|
|
427
|
+
window_group: int | None = None,
|
|
428
|
+
urgent: bool | None = None,
|
|
429
|
+
) -> None:
|
|
430
|
+
"""Apply ICCCM window-manager hints to *window*.
|
|
431
|
+
|
|
432
|
+
Pass individual fields, or supply a pre-built 9-element list via *data*.
|
|
433
|
+
When *data* is given it takes precedence over the keyword fields.
|
|
434
|
+
|
|
435
|
+
Examples
|
|
436
|
+
--------
|
|
437
|
+
Normal window that accepts keyboard focus::
|
|
438
|
+
|
|
439
|
+
await set_wm_hints(wnd, input=True, initial_state=InitialState.Normal)
|
|
440
|
+
|
|
441
|
+
Start iconic (minimized)::
|
|
442
|
+
|
|
443
|
+
await set_wm_hints(wnd, initial_state=InitialState.Iconic)
|
|
444
|
+
|
|
445
|
+
Mark urgent (attention)::
|
|
446
|
+
|
|
447
|
+
await set_wm_hints(wnd, urgent=True)
|
|
448
|
+
"""
|
|
449
|
+
data = build_wm_hints(
|
|
450
|
+
input=input,
|
|
451
|
+
initial_state=initial_state,
|
|
452
|
+
icon_pixmap=icon_pixmap,
|
|
453
|
+
icon_window=icon_window,
|
|
454
|
+
icon_x=icon_x,
|
|
455
|
+
icon_y=icon_y,
|
|
456
|
+
icon_mask=icon_mask,
|
|
457
|
+
window_group=window_group,
|
|
458
|
+
urgent=urgent,
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
await window.change_property(
|
|
462
|
+
Atom.WM_HINTS,
|
|
463
|
+
Atom.WM_HINTS,
|
|
464
|
+
32,
|
|
465
|
+
data,
|
|
413
466
|
)
|
|
414
467
|
|
|
415
468
|
async def change_text_property(self, property, data, property_type=Atom.STRING, mode=PropMode.Replace):
|
|
@@ -28,6 +28,7 @@ from .constants import (
|
|
|
28
28
|
ConfigureWindowAttributes,
|
|
29
29
|
CreateWindowAttributes,
|
|
30
30
|
EventType,
|
|
31
|
+
InitialState,
|
|
31
32
|
MotifDecor,
|
|
32
33
|
MotifFunc,
|
|
33
34
|
MotifHintsFlag,
|
|
@@ -35,6 +36,7 @@ from .constants import (
|
|
|
35
36
|
SizeHintsFlag,
|
|
36
37
|
VisualClass,
|
|
37
38
|
WinGravity,
|
|
39
|
+
WMHintsFlag,
|
|
38
40
|
)
|
|
39
41
|
|
|
40
42
|
log = logging.getLogger("aioxlib")
|
|
@@ -1778,3 +1780,107 @@ def build_size_hints(
|
|
|
1778
1780
|
vals["base_height"],
|
|
1779
1781
|
vals["win_gravity"],
|
|
1780
1782
|
]
|
|
1783
|
+
|
|
1784
|
+
|
|
1785
|
+
def build_wm_hints(
|
|
1786
|
+
*,
|
|
1787
|
+
input: bool | None = None,
|
|
1788
|
+
initial_state: InitialState | int | None = None,
|
|
1789
|
+
icon_pixmap: int | None = None,
|
|
1790
|
+
icon_window: int | None = None,
|
|
1791
|
+
icon_x: int | None = None,
|
|
1792
|
+
icon_y: int | None = None,
|
|
1793
|
+
icon_mask: int | None = None,
|
|
1794
|
+
window_group: int | None = None,
|
|
1795
|
+
urgent: bool | None = None,
|
|
1796
|
+
) -> list[int]:
|
|
1797
|
+
"""Build the 9-element ``XWMHints`` payload for ``WM_HINTS``.
|
|
1798
|
+
|
|
1799
|
+
Only fields that are not ``None`` are marked valid in ``flags``.
|
|
1800
|
+
Omitted fields are written as ``0`` and ignored by the WM.
|
|
1801
|
+
|
|
1802
|
+
Parameters
|
|
1803
|
+
----------
|
|
1804
|
+
input :
|
|
1805
|
+
If True, the application expects the WM to set input focus
|
|
1806
|
+
(typical for Normal windows). If False, the client sets focus itself.
|
|
1807
|
+
initial_state :
|
|
1808
|
+
``InitialState.Normal`` or ``InitialState.Iconic`` (or Withdrawn).
|
|
1809
|
+
icon_pixmap :
|
|
1810
|
+
Pixmap id to use as the icon image.
|
|
1811
|
+
icon_window :
|
|
1812
|
+
Window id to use as the icon (alternative to pixmap).
|
|
1813
|
+
icon_x, icon_y :
|
|
1814
|
+
Preferred icon position on the root / desktop.
|
|
1815
|
+
icon_mask :
|
|
1816
|
+
Pixmap id used as a mask for ``icon_pixmap``.
|
|
1817
|
+
window_group :
|
|
1818
|
+
Leader window id for a group of related windows.
|
|
1819
|
+
urgent :
|
|
1820
|
+
If True, set the UrgencyHint bit (WM may flash the title / taskbar).
|
|
1821
|
+
|
|
1822
|
+
Returns
|
|
1823
|
+
-------
|
|
1824
|
+
list of 9 ints
|
|
1825
|
+
Ready to pass to ``change_property(..., format=32, data=...)``.
|
|
1826
|
+
"""
|
|
1827
|
+
flags = 0
|
|
1828
|
+
vals = {
|
|
1829
|
+
"input": 0,
|
|
1830
|
+
"initial_state": 0,
|
|
1831
|
+
"icon_pixmap": 0,
|
|
1832
|
+
"icon_window": 0,
|
|
1833
|
+
"icon_x": 0,
|
|
1834
|
+
"icon_y": 0,
|
|
1835
|
+
"icon_mask": 0,
|
|
1836
|
+
"window_group": 0,
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
if input is not None:
|
|
1840
|
+
flags |= WMHintsFlag.InputHint
|
|
1841
|
+
vals["input"] = 1 if input else 0
|
|
1842
|
+
|
|
1843
|
+
if initial_state is not None:
|
|
1844
|
+
flags |= WMHintsFlag.StateHint
|
|
1845
|
+
vals["initial_state"] = int(initial_state)
|
|
1846
|
+
|
|
1847
|
+
if icon_pixmap is not None:
|
|
1848
|
+
flags |= WMHintsFlag.IconPixmapHint
|
|
1849
|
+
vals["icon_pixmap"] = int(icon_pixmap)
|
|
1850
|
+
|
|
1851
|
+
if icon_window is not None:
|
|
1852
|
+
flags |= WMHintsFlag.IconWindowHint
|
|
1853
|
+
vals["icon_window"] = int(icon_window)
|
|
1854
|
+
|
|
1855
|
+
if icon_x is not None or icon_y is not None:
|
|
1856
|
+
flags |= WMHintsFlag.IconPositionHint
|
|
1857
|
+
if icon_x is not None:
|
|
1858
|
+
vals["icon_x"] = int(icon_x)
|
|
1859
|
+
if icon_y is not None:
|
|
1860
|
+
vals["icon_y"] = int(icon_y)
|
|
1861
|
+
|
|
1862
|
+
if icon_mask is not None:
|
|
1863
|
+
flags |= WMHintsFlag.IconMaskHint
|
|
1864
|
+
vals["icon_mask"] = int(icon_mask)
|
|
1865
|
+
|
|
1866
|
+
if window_group is not None:
|
|
1867
|
+
flags |= WMHintsFlag.WindowGroupHint
|
|
1868
|
+
vals["window_group"] = int(window_group)
|
|
1869
|
+
|
|
1870
|
+
if urgent is not None:
|
|
1871
|
+
if urgent:
|
|
1872
|
+
flags |= WMHintsFlag.UrgencyHint
|
|
1873
|
+
# When urgent=False we still leave UrgencyHint unset (not valid),
|
|
1874
|
+
# which clears urgency for WMs that replace the whole property.
|
|
1875
|
+
|
|
1876
|
+
return [
|
|
1877
|
+
flags,
|
|
1878
|
+
vals["input"],
|
|
1879
|
+
vals["initial_state"],
|
|
1880
|
+
vals["icon_pixmap"],
|
|
1881
|
+
vals["icon_window"],
|
|
1882
|
+
vals["icon_x"],
|
|
1883
|
+
vals["icon_y"],
|
|
1884
|
+
vals["icon_mask"],
|
|
1885
|
+
vals["window_group"],
|
|
1886
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aioxlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.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
|
|
@@ -31,18 +31,42 @@ Dynamic: license-file
|
|
|
31
31
|
[](https://pypi.org/project/aioxlib/)
|
|
32
32
|
[](https://pypi.org/project/aioxlib/)
|
|
33
33
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
34
|
+
[](https://aioxlib.readthedocs.io)
|
|
34
35
|
|
|
35
|
-
`aioxlib` is a pure-Python
|
|
36
|
-
|
|
36
|
+
`aioxlib` is a **pure-Python**, **asyncio-native** client for the X11 wire protocol.
|
|
37
|
+
Open displays, create windows, draw with GCs and the RENDER extension, and stream
|
|
38
|
+
events — without blocking the event loop and without linking to libX11 or xcb.
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img src="docs/images/game_of_life.gif" style="height: 300px;" alt="Conway's Game of Life on X11 via aioxlib"/>
|
|
42
|
+
|
|
43
|
+
<img src="docs/images/3d_cube.gif" style="height: 300px;" alt="Rotating 3D wireframe via aioxlib"/>
|
|
44
|
+
</p>
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
- Local: `pip install --group docs && mkdocs serve`
|
|
46
|
+
<p align="center"><em>Examples shipped with the library: Game of Life · 3D wireframe</em></p>
|
|
42
47
|
|
|
43
|
-
##
|
|
48
|
+
## Why aioxlib?
|
|
49
|
+
|
|
50
|
+
| | **aioxlib** | python-xlib | xcffib / xpyb |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| Language | Pure Python | Pure Python | C (libxcb) + Python |
|
|
53
|
+
| Async | **asyncio first** | Blocking / threads | Blocking |
|
|
54
|
+
| Dependencies | None at runtime | None | libxcb |
|
|
55
|
+
| Protocol access | Pack/unpack helpers exposed | High-level only | Low-level |
|
|
56
|
+
| Extensions | RENDER, MIT-SHM, DBE, GLX, … | Many | Many |
|
|
57
|
+
|
|
58
|
+
Inspired by [linuxpy](https://github.com/tiagocoutinho/linuxpy) (same author):
|
|
59
|
+
a clean high-level API when you want it, full protocol detail when you need it.
|
|
60
|
+
|
|
61
|
+
## Requirements
|
|
62
|
+
|
|
63
|
+
- **Python ≥ 3.12**
|
|
64
|
+
- An X server (local or remote) and network/socket access to it
|
|
65
|
+
(`$DISPLAY` or an explicit URI)
|
|
44
66
|
|
|
45
|
-
|
|
67
|
+
No third-party Python packages are required at runtime.
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
46
70
|
|
|
47
71
|
```bash
|
|
48
72
|
pip install aioxlib
|
|
@@ -50,7 +74,7 @@ pip install aioxlib
|
|
|
50
74
|
|
|
51
75
|
## Quick start
|
|
52
76
|
|
|
53
|
-
|
|
77
|
+
### Functional API (simplest)
|
|
54
78
|
|
|
55
79
|
```python
|
|
56
80
|
import asyncio
|
|
@@ -91,19 +115,49 @@ async def main():
|
|
|
91
115
|
asyncio.run(main())
|
|
92
116
|
```
|
|
93
117
|
|
|
118
|
+
## Features
|
|
119
|
+
|
|
120
|
+
- **Windows & drawing** — create/map/configure windows, GCs, polylines, rectangles, arcs, text, images
|
|
121
|
+
- **Events** — non-blocking `async for event in display.events()` stream
|
|
122
|
+
- **Properties & atoms** — `WM_NAME`, protocols, custom properties
|
|
123
|
+
- **Extensions** — BIG-REQUESTS, RENDER, MIT-SHM, DBE, GLX, RANDR, DRI3, Present
|
|
124
|
+
- **Pipeline** — batch requests with `async with display.pipeline(): …`
|
|
125
|
+
- **Protocol transparent** — opcodes, pack/unpack helpers stay accessible
|
|
126
|
+
|
|
127
|
+
## Examples
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# clone the repo, then:
|
|
131
|
+
python examples/basic.py
|
|
132
|
+
python examples/game_of_life.py # Conway's Life (numpy)
|
|
133
|
+
python examples/3d.py # rotating 3D mesh
|
|
134
|
+
python examples/video_shm_dbe.py # shared memory + double buffering
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Example | What it shows |
|
|
138
|
+
|---------|----------------|
|
|
139
|
+
| `basic.py` | Window + delete protocol |
|
|
140
|
+
| `game_of_life.py` | Animated cellular automaton |
|
|
141
|
+
| `3d.py` | Perspective projection & wireframe |
|
|
142
|
+
| `render.py` / `tristrip.py` | RENDER extension |
|
|
143
|
+
| `shm.py` / `video_shm*.py` | MIT-SHM image transfer |
|
|
144
|
+
| `cube_dbe.py` | Double buffering (DBE) |
|
|
145
|
+
| `keyboard.py` | Key events |
|
|
146
|
+
|
|
94
147
|
## Package layout
|
|
95
148
|
|
|
96
149
|
| Module | Contents |
|
|
97
150
|
|--------|----------|
|
|
98
|
-
| **`aioxlib`** (root) |
|
|
151
|
+
| **`aioxlib`** (root) | Functional API + `get_display` + common constants |
|
|
99
152
|
| `aioxlib.constants` | X11 constants and enumerations |
|
|
100
|
-
| `aioxlib.protocol` |
|
|
153
|
+
| `aioxlib.protocol` | Pack/unpack helpers |
|
|
101
154
|
| `aioxlib.connection` | Socket connection, Xauthority |
|
|
102
|
-
| `aioxlib.
|
|
103
|
-
| `aioxlib.display` (Window, Screen, GC, …) | Window, Screen, GC |
|
|
104
|
-
| `aioxlib.display` | Display, Pipeline |
|
|
155
|
+
| `aioxlib.display` | `Display`, `Screen`, `Window`, `GC`, `Pipeline` |
|
|
105
156
|
| `aioxlib.render` / `shm` / `dbe` / … | Extensions |
|
|
106
157
|
|
|
158
|
+
Classes such as `Display`, `Window`, and `EventType` are imported from their
|
|
159
|
+
modules (or from the root where re-exported).
|
|
160
|
+
|
|
107
161
|
### Root functional API (selection)
|
|
108
162
|
|
|
109
163
|
| Function | Role |
|
|
@@ -114,28 +168,16 @@ asyncio.run(main())
|
|
|
114
168
|
| `flush`, `query_extension`, `get_atom`, … | Display operations |
|
|
115
169
|
| `close_default_display` | Tear down default connection |
|
|
116
170
|
|
|
117
|
-
Classes such as `Display`, `Window`, and `EventType` are **not** re-exported
|
|
118
|
-
from the root; import them from their modules.
|
|
119
|
-
|
|
120
171
|
## Documentation
|
|
121
172
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
mkdocs serve
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
## Examples
|
|
173
|
+
- Online: [aioxlib.readthedocs.io](https://aioxlib.readthedocs.io)
|
|
174
|
+
- Local:
|
|
128
175
|
|
|
129
176
|
```bash
|
|
130
|
-
python
|
|
131
|
-
|
|
177
|
+
pip install --group docs # or: pip install mkdocs mkdocs-material 'mkdocstrings[python]'
|
|
178
|
+
mkdocs serve
|
|
132
179
|
```
|
|
133
180
|
|
|
134
|
-
## Requirements
|
|
135
|
-
|
|
136
|
-
- Python ≥ 3.12
|
|
137
|
-
- An X11 server and `$DISPLAY` (or an explicit URI)
|
|
138
|
-
|
|
139
181
|
## License
|
|
140
182
|
|
|
141
183
|
GPLv3 or later — see [LICENSE](LICENSE).
|
|
@@ -545,7 +545,7 @@ class TestScreen:
|
|
|
545
545
|
assert payload[1] == 24
|
|
546
546
|
|
|
547
547
|
@pytest.mark.asyncio
|
|
548
|
-
async def
|
|
548
|
+
async def test_create_window_explicit_parent(self, display):
|
|
549
549
|
screen = display.screens[0]
|
|
550
550
|
parent = Window(display, 0x50)
|
|
551
551
|
_ = await screen.create_window(width=100, height=100, parent=parent, depth=16)
|
|
@@ -47,18 +47,22 @@ from aioxlib.connection import (
|
|
|
47
47
|
)
|
|
48
48
|
from aioxlib.constants import (
|
|
49
49
|
XSIZE_HINTS_LEN,
|
|
50
|
+
XWM_HINTS_LEN,
|
|
51
|
+
InitialState,
|
|
50
52
|
MotifDecor,
|
|
51
53
|
MotifFunc,
|
|
52
54
|
MotifHintsFlag,
|
|
53
55
|
MotifInputMode,
|
|
54
56
|
SizeHintsFlag,
|
|
55
57
|
WinGravity,
|
|
58
|
+
WMHintsFlag,
|
|
56
59
|
)
|
|
57
60
|
from aioxlib.protocol import (
|
|
58
61
|
EVENT_HANDLERS,
|
|
59
62
|
build_font,
|
|
60
63
|
build_motif_wm_hints,
|
|
61
64
|
build_size_hints,
|
|
65
|
+
build_wm_hints,
|
|
62
66
|
decode_property_value,
|
|
63
67
|
encode_property_value,
|
|
64
68
|
pack_change_property,
|
|
@@ -2090,3 +2094,96 @@ class TestSizeHintsFlagValues:
|
|
|
2090
2094
|
assert WinGravity.NorthWest == 1
|
|
2091
2095
|
assert WinGravity.Center == 5
|
|
2092
2096
|
assert WinGravity.Static == 10
|
|
2097
|
+
|
|
2098
|
+
|
|
2099
|
+
class TestBuildWmHints:
|
|
2100
|
+
def test_empty(self):
|
|
2101
|
+
data = build_wm_hints()
|
|
2102
|
+
assert len(data) == XWM_HINTS_LEN
|
|
2103
|
+
assert data == [0] * XWM_HINTS_LEN
|
|
2104
|
+
|
|
2105
|
+
def test_input_and_state(self):
|
|
2106
|
+
data = build_wm_hints(input=True, initial_state=InitialState.Normal)
|
|
2107
|
+
flags = data[0]
|
|
2108
|
+
assert flags == WMHintsFlag.InputHint | WMHintsFlag.StateHint
|
|
2109
|
+
assert data[1] == 1 # input
|
|
2110
|
+
assert data[2] == InitialState.Normal
|
|
2111
|
+
|
|
2112
|
+
def test_iconic(self):
|
|
2113
|
+
data = build_wm_hints(initial_state=InitialState.Iconic)
|
|
2114
|
+
assert data[0] == WMHintsFlag.StateHint
|
|
2115
|
+
assert data[2] == InitialState.Iconic
|
|
2116
|
+
|
|
2117
|
+
def test_urgent(self):
|
|
2118
|
+
data = build_wm_hints(urgent=True)
|
|
2119
|
+
assert data[0] == WMHintsFlag.UrgencyHint
|
|
2120
|
+
# no other fields set
|
|
2121
|
+
assert data[1:] == [0] * (XWM_HINTS_LEN - 1)
|
|
2122
|
+
|
|
2123
|
+
def test_urgent_false_clears_bit(self):
|
|
2124
|
+
data = build_wm_hints(urgent=False)
|
|
2125
|
+
assert data[0] & WMHintsFlag.UrgencyHint == 0
|
|
2126
|
+
|
|
2127
|
+
def test_icon_pixmap_and_mask(self):
|
|
2128
|
+
data = build_wm_hints(icon_pixmap=0xABC, icon_mask=0xDEF)
|
|
2129
|
+
assert data[0] == WMHintsFlag.IconPixmapHint | WMHintsFlag.IconMaskHint
|
|
2130
|
+
assert data[3] == 0xABC
|
|
2131
|
+
assert data[7] == 0xDEF
|
|
2132
|
+
|
|
2133
|
+
def test_icon_window(self):
|
|
2134
|
+
data = build_wm_hints(icon_window=0x1234)
|
|
2135
|
+
assert data[0] == WMHintsFlag.IconWindowHint
|
|
2136
|
+
assert data[4] == 0x1234
|
|
2137
|
+
|
|
2138
|
+
def test_icon_position(self):
|
|
2139
|
+
data = build_wm_hints(icon_x=10, icon_y=20)
|
|
2140
|
+
assert data[0] == WMHintsFlag.IconPositionHint
|
|
2141
|
+
assert data[5] == 10
|
|
2142
|
+
assert data[6] == 20
|
|
2143
|
+
|
|
2144
|
+
def test_window_group(self):
|
|
2145
|
+
data = build_wm_hints(window_group=0x999)
|
|
2146
|
+
assert data[0] == WMHintsFlag.WindowGroupHint
|
|
2147
|
+
assert data[8] == 0x999
|
|
2148
|
+
|
|
2149
|
+
def test_all_fields(self):
|
|
2150
|
+
data = build_wm_hints(
|
|
2151
|
+
input=True,
|
|
2152
|
+
initial_state=InitialState.Normal,
|
|
2153
|
+
icon_pixmap=1,
|
|
2154
|
+
icon_window=2,
|
|
2155
|
+
icon_x=3,
|
|
2156
|
+
icon_y=4,
|
|
2157
|
+
icon_mask=5,
|
|
2158
|
+
window_group=6,
|
|
2159
|
+
urgent=True,
|
|
2160
|
+
)
|
|
2161
|
+
expected_flags = (
|
|
2162
|
+
WMHintsFlag.InputHint
|
|
2163
|
+
| WMHintsFlag.StateHint
|
|
2164
|
+
| WMHintsFlag.IconPixmapHint
|
|
2165
|
+
| WMHintsFlag.IconWindowHint
|
|
2166
|
+
| WMHintsFlag.IconPositionHint
|
|
2167
|
+
| WMHintsFlag.IconMaskHint
|
|
2168
|
+
| WMHintsFlag.WindowGroupHint
|
|
2169
|
+
| WMHintsFlag.UrgencyHint
|
|
2170
|
+
)
|
|
2171
|
+
assert data[0] == expected_flags
|
|
2172
|
+
assert data[1:] == [1, 1, 1, 2, 3, 4, 5, 6]
|
|
2173
|
+
|
|
2174
|
+
|
|
2175
|
+
class TestWMHintsFlagValues:
|
|
2176
|
+
def test_wm_hints_flags(self):
|
|
2177
|
+
assert WMHintsFlag.InputHint == 1
|
|
2178
|
+
assert WMHintsFlag.StateHint == 2
|
|
2179
|
+
assert WMHintsFlag.IconPixmapHint == 4
|
|
2180
|
+
assert WMHintsFlag.IconWindowHint == 8
|
|
2181
|
+
assert WMHintsFlag.IconPositionHint == 16
|
|
2182
|
+
assert WMHintsFlag.IconMaskHint == 32
|
|
2183
|
+
assert WMHintsFlag.WindowGroupHint == 64
|
|
2184
|
+
assert WMHintsFlag.UrgencyHint == 256
|
|
2185
|
+
|
|
2186
|
+
def test_initial_states(self):
|
|
2187
|
+
assert InitialState.Withdrawn == 0
|
|
2188
|
+
assert InitialState.Normal == 1
|
|
2189
|
+
assert InitialState.Iconic == 3
|
aioxlib-0.7.1/README.md
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# aioxlib
|
|
2
|
-
|
|
3
|
-
**Human-friendly asyncio interface to the X11 protocol**
|
|
4
|
-
|
|
5
|
-
[](https://pypi.org/project/aioxlib/)
|
|
6
|
-
[](https://pypi.org/project/aioxlib/)
|
|
7
|
-
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
8
|
-
|
|
9
|
-
`aioxlib` is a pure-Python library that speaks the X11 wire protocol over
|
|
10
|
-
asyncio—without blocking the event loop and without linking to libX11.
|
|
11
|
-
|
|
12
|
-
## Documentation
|
|
13
|
-
|
|
14
|
-
- Online: [aioxlib.readthedocs.io](https://aioxlib.readthedocs.io)
|
|
15
|
-
- Local: `pip install --group docs && mkdocs serve`
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
From within your favorite python environment:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
pip install aioxlib
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Quick start
|
|
26
|
-
|
|
27
|
-
The **root package** exposes the functional API and `get_display` only:
|
|
28
|
-
|
|
29
|
-
```python
|
|
30
|
-
import asyncio
|
|
31
|
-
import aioxlib
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
async def main():
|
|
35
|
-
wnd = await aioxlib.create_window(640, 480, title="Hello from aioxlib")
|
|
36
|
-
await wnd.show()
|
|
37
|
-
|
|
38
|
-
async for event in aioxlib.events():
|
|
39
|
-
if wnd.is_delete_window(event):
|
|
40
|
-
break
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
asyncio.run(main())
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Explicit display (object API)
|
|
47
|
-
|
|
48
|
-
```python
|
|
49
|
-
import asyncio
|
|
50
|
-
import aioxlib
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
async def main():
|
|
54
|
-
display = await aioxlib.get_display()
|
|
55
|
-
async with display:
|
|
56
|
-
screen = display.default_screen()
|
|
57
|
-
wnd = await screen.create_window(640, 480, title="Hello from aioxlib")
|
|
58
|
-
await wnd.show()
|
|
59
|
-
|
|
60
|
-
async for event in display.events():
|
|
61
|
-
if wnd.is_delete_window(event):
|
|
62
|
-
break
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
asyncio.run(main())
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Package layout
|
|
69
|
-
|
|
70
|
-
| Module | Contents |
|
|
71
|
-
|--------|----------|
|
|
72
|
-
| **`aioxlib`** (root) | Constants/enums + functional API + `get_display` |
|
|
73
|
-
| `aioxlib.constants` | X11 constants and enumerations |
|
|
74
|
-
| `aioxlib.protocol` | Constants, enums, pack/unpack |
|
|
75
|
-
| `aioxlib.connection` | Socket connection, Xauthority |
|
|
76
|
-
| `aioxlib.resource` | Resource, Drawable, ResourceManager |
|
|
77
|
-
| `aioxlib.display` (Window, Screen, GC, …) | Window, Screen, GC |
|
|
78
|
-
| `aioxlib.display` | Display, Pipeline |
|
|
79
|
-
| `aioxlib.render` / `shm` / `dbe` / … | Extensions |
|
|
80
|
-
|
|
81
|
-
### Root functional API (selection)
|
|
82
|
-
|
|
83
|
-
| Function | Role |
|
|
84
|
-
|----------|------|
|
|
85
|
-
| `get_display` / `get_default_display` | Open connection |
|
|
86
|
-
| `create_window`, `map_window`, … | Windows |
|
|
87
|
-
| `events()`, `pipeline()` | Event stream / batched writes |
|
|
88
|
-
| `flush`, `query_extension`, `get_atom`, … | Display operations |
|
|
89
|
-
| `close_default_display` | Tear down default connection |
|
|
90
|
-
|
|
91
|
-
Classes such as `Display`, `Window`, and `EventType` are **not** re-exported
|
|
92
|
-
from the root; import them from their modules.
|
|
93
|
-
|
|
94
|
-
## Documentation
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
pip install mkdocs mkdocs-material 'mkdocstrings[python]'
|
|
98
|
-
mkdocs serve
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Examples
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
python examples/basic.py
|
|
105
|
-
python examples/functional.py
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Requirements
|
|
109
|
-
|
|
110
|
-
- Python ≥ 3.12
|
|
111
|
-
- An X11 server and `$DISPLAY` (or an explicit URI)
|
|
112
|
-
|
|
113
|
-
## License
|
|
114
|
-
|
|
115
|
-
GPLv3 or later — see [LICENSE](LICENSE).
|
|
116
|
-
|
|
117
|
-
## Author
|
|
118
|
-
|
|
119
|
-
José Tiago Macara Coutinho
|
|
120
|
-
<https://codeberg.org/tiagocoutinho>
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|