aioxlib 0.7.2__tar.gz → 0.9.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.2 → aioxlib-0.9.0}/PKG-INFO +3 -3
- {aioxlib-0.7.2 → aioxlib-0.9.0}/README.md +2 -2
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/__init__.py +1 -1
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/api.py +21 -1
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/constants.py +53 -1
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/display.py +159 -27
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/protocol.py +227 -1
- aioxlib-0.9.0/aioxlib/stream.py +145 -0
- aioxlib-0.9.0/aioxlib/widgets.py +428 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib.egg-info/PKG-INFO +3 -3
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib.egg-info/SOURCES.txt +1 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_display.py +1 -1
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_protocol.py +97 -0
- aioxlib-0.7.2/aioxlib/widgets.py +0 -211
- {aioxlib-0.7.2 → aioxlib-0.9.0}/LICENSE +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/_extensions.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/authority.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/bigreq.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/connection.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/dbe.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/dri3.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/glx.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/present.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/randr.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/render.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib/shm.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib.egg-info/dependency_links.txt +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/aioxlib.egg-info/top_level.txt +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/pyproject.toml +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/setup.cfg +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_api.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_authority.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_bigreq.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_connection.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_constants.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_dbe.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_dri3.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_examples.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_extensions.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_glx.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_present.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_randr.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_render.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.0}/tests/test_shm.py +0 -0
- {aioxlib-0.7.2 → aioxlib-0.9.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.9.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
|
|
@@ -38,9 +38,9 @@ Open displays, create windows, draw with GCs and the RENDER extension, and strea
|
|
|
38
38
|
events — without blocking the event loop and without linking to libX11 or xcb.
|
|
39
39
|
|
|
40
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"/>
|
|
41
|
+
<img src="docs/images/game_of_life.gif" style="height: 300px;" height="300" alt="Conway's Game of Life on X11 via aioxlib"/>
|
|
42
42
|
|
|
43
|
-
<img src="docs/images/3d_cube.gif" style="height: 300px;" alt="Rotating 3D wireframe via aioxlib"/>
|
|
43
|
+
<img src="docs/images/3d_cube.gif" style="height: 300px;" height="300" alt="Rotating 3D wireframe via aioxlib"/>
|
|
44
44
|
</p>
|
|
45
45
|
|
|
46
46
|
<p align="center"><em>Examples shipped with the library: Game of Life · 3D wireframe</em></p>
|
|
@@ -12,9 +12,9 @@ Open displays, create windows, draw with GCs and the RENDER extension, and strea
|
|
|
12
12
|
events — without blocking the event loop and without linking to libX11 or xcb.
|
|
13
13
|
|
|
14
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"/>
|
|
15
|
+
<img src="docs/images/game_of_life.gif" style="height: 300px;" height="300" alt="Conway's Game of Life on X11 via aioxlib"/>
|
|
16
16
|
|
|
17
|
-
<img src="docs/images/3d_cube.gif" style="height: 300px;" alt="Rotating 3D wireframe via aioxlib"/>
|
|
17
|
+
<img src="docs/images/3d_cube.gif" style="height: 300px;" height="300" alt="Rotating 3D wireframe via aioxlib"/>
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center"><em>Examples shipped with the library: Game of Life · 3D wireframe</em></p>
|
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
from .constants import (
|
|
10
10
|
Allocate,
|
|
11
11
|
AnyPropertyType,
|
|
12
|
+
CoordinateMode,
|
|
12
13
|
PropMode,
|
|
13
14
|
)
|
|
14
15
|
from .display import Display
|
|
@@ -307,6 +308,17 @@ async def open_font(name=None, display: Display | None = None, **kwargs):
|
|
|
307
308
|
return await d.open_font(name=name, **kwargs)
|
|
308
309
|
|
|
309
310
|
|
|
311
|
+
async def query_text_extents(font, string, display: Display | None = None):
|
|
312
|
+
"""QueryTextExtents — bounding box of *string* in *font* (or GC).
|
|
313
|
+
|
|
314
|
+
Returns a dict with draw_direction, font_ascent, font_descent,
|
|
315
|
+
overall_ascent, overall_descent, overall_width, overall_left,
|
|
316
|
+
overall_right.
|
|
317
|
+
"""
|
|
318
|
+
d = await _resolve_display(display)
|
|
319
|
+
return await d.query_text_extents(font, string)
|
|
320
|
+
|
|
321
|
+
|
|
310
322
|
async def tree(wnd, display: Display | None = None):
|
|
311
323
|
"""Query the window tree for *wnd*."""
|
|
312
324
|
d = await _resolve_display(display)
|
|
@@ -331,12 +343,18 @@ async def poly_segments(drawable, gc, segments, display: Display | None = None):
|
|
|
331
343
|
return await d.poly_segments(drawable, gc, segments)
|
|
332
344
|
|
|
333
345
|
|
|
334
|
-
async def poly_points(drawable, gc, points, mode, display: Display | None = None):
|
|
346
|
+
async def poly_points(drawable, gc, points, mode=CoordinateMode.Origin, display: Display | None = None):
|
|
335
347
|
"""PolyPoint on *drawable*."""
|
|
336
348
|
d = await _resolve_display(display)
|
|
337
349
|
return await d.poly_points(drawable, gc, points, mode)
|
|
338
350
|
|
|
339
351
|
|
|
352
|
+
async def poly_lines(drawable, gc, points, mode=CoordinateMode.Origin, display: Display | None = None):
|
|
353
|
+
"""PolyLine on *drawable*."""
|
|
354
|
+
d = await _resolve_display(display)
|
|
355
|
+
return await d.poly_lines(drawable, gc, points, mode)
|
|
356
|
+
|
|
357
|
+
|
|
340
358
|
async def clear_area(wnd, x, y, w, h, exposure=False, display: Display | None = None):
|
|
341
359
|
"""ClearArea on *wnd*."""
|
|
342
360
|
d = await _resolve_display(display)
|
|
@@ -421,11 +439,13 @@ __all__ = [
|
|
|
421
439
|
"delete_property",
|
|
422
440
|
"open_font_name",
|
|
423
441
|
"open_font",
|
|
442
|
+
"query_text_extents",
|
|
424
443
|
"tree",
|
|
425
444
|
"poly_fill_rectangles",
|
|
426
445
|
"poly_fill_arcs",
|
|
427
446
|
"poly_segments",
|
|
428
447
|
"poly_points",
|
|
448
|
+
"poly_lines",
|
|
429
449
|
"clear_area",
|
|
430
450
|
"set_input_focus",
|
|
431
451
|
"get_geometry",
|
|
@@ -282,9 +282,25 @@ class Command(enum.IntEnum):
|
|
|
282
282
|
FreeColormap = 79
|
|
283
283
|
QueryExtension = 98
|
|
284
284
|
ListExtensions = 99
|
|
285
|
-
|
|
285
|
+
ChangeKeyboardMapping = 100
|
|
286
|
+
GetKeyboardMapping = 101
|
|
287
|
+
ChangeKeyboardControl = 102
|
|
288
|
+
GetKeyboardControl = 103
|
|
289
|
+
Bell = 104
|
|
290
|
+
ChangePointerControl = 105
|
|
291
|
+
GetPointerControl = 106
|
|
286
292
|
SetScreenSaver = 107
|
|
287
293
|
GetScreenSaver = 108
|
|
294
|
+
ChangeHosts = 109
|
|
295
|
+
ListHosts = 110
|
|
296
|
+
SetAccessControl = 111
|
|
297
|
+
SetCloseDownMode = 112
|
|
298
|
+
KillClient = 113
|
|
299
|
+
RotateProperties = 114
|
|
300
|
+
ForceScreenSaver = 115
|
|
301
|
+
SetPointerMapping = 116
|
|
302
|
+
GetPointerMapping = 117
|
|
303
|
+
SetModifierMapping = 118
|
|
288
304
|
GetModifierMapping = 119
|
|
289
305
|
NoOperation = 127
|
|
290
306
|
|
|
@@ -925,6 +941,36 @@ class WinGravity(enum.IntEnum):
|
|
|
925
941
|
Static = 10
|
|
926
942
|
|
|
927
943
|
|
|
944
|
+
# Number of 32-bit fields in the ICCCM / Xlib XWMHints structure
|
|
945
|
+
XWM_HINTS_LEN = 9
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
class WMHintsFlag(enum.IntFlag):
|
|
949
|
+
"""Bits for the ``flags`` field — which of the following fields are valid.
|
|
950
|
+
|
|
951
|
+
Values match the ICCCM / Xlib ``XWMHints`` definition.
|
|
952
|
+
"""
|
|
953
|
+
|
|
954
|
+
InputHint = 1 << 0
|
|
955
|
+
StateHint = 1 << 1
|
|
956
|
+
IconPixmapHint = 1 << 2
|
|
957
|
+
IconWindowHint = 1 << 3
|
|
958
|
+
IconPositionHint = 1 << 4
|
|
959
|
+
IconMaskHint = 1 << 5
|
|
960
|
+
WindowGroupHint = 1 << 6
|
|
961
|
+
# bit 7 was WithdrawnHint (obsolete)
|
|
962
|
+
UrgencyHint = 1 << 8
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
class InitialState(enum.IntEnum):
|
|
966
|
+
"""Values for the ``initial_state`` field."""
|
|
967
|
+
|
|
968
|
+
Withdrawn = 0
|
|
969
|
+
Normal = 1
|
|
970
|
+
# 2 was ZoomState (obsolete)
|
|
971
|
+
Iconic = 3
|
|
972
|
+
|
|
973
|
+
|
|
928
974
|
LSBFirst = 0
|
|
929
975
|
|
|
930
976
|
MSBFirst = 1
|
|
@@ -1148,6 +1194,12 @@ __all__ = [
|
|
|
1148
1194
|
"MotifFunc",
|
|
1149
1195
|
"MotifDecor",
|
|
1150
1196
|
"MotifInputMode",
|
|
1197
|
+
"XSIZE_HINTS_LEN",
|
|
1198
|
+
"SizeHintsFlag",
|
|
1199
|
+
"WinGravity",
|
|
1200
|
+
"XWM_HINTS_LEN",
|
|
1201
|
+
"WMHintsFlag",
|
|
1202
|
+
"InitialState",
|
|
1151
1203
|
"LSBFirst",
|
|
1152
1204
|
"MSBFirst",
|
|
1153
1205
|
"GenericEventCode",
|
|
@@ -17,6 +17,7 @@ import asyncio
|
|
|
17
17
|
import logging
|
|
18
18
|
import os
|
|
19
19
|
|
|
20
|
+
from . import protocol
|
|
20
21
|
from .connection import open_connection
|
|
21
22
|
from .constants import (
|
|
22
23
|
BYTE_ORDER_TEXT,
|
|
@@ -28,10 +29,12 @@ from .constants import (
|
|
|
28
29
|
AnyPropertyType,
|
|
29
30
|
Atom,
|
|
30
31
|
Command,
|
|
32
|
+
CoordinateMode,
|
|
31
33
|
CopyFromParent,
|
|
32
34
|
ErrorCode,
|
|
33
35
|
EventType,
|
|
34
36
|
ImageFormat,
|
|
37
|
+
InitialState,
|
|
35
38
|
PropMode,
|
|
36
39
|
StackMode,
|
|
37
40
|
Status,
|
|
@@ -42,6 +45,7 @@ from .protocol import (
|
|
|
42
45
|
build_font,
|
|
43
46
|
build_motif_wm_hints,
|
|
44
47
|
build_size_hints,
|
|
48
|
+
build_wm_hints,
|
|
45
49
|
pack_change_property,
|
|
46
50
|
pack_clear_area,
|
|
47
51
|
pack_configure_window,
|
|
@@ -57,6 +61,7 @@ from .protocol import (
|
|
|
57
61
|
pack_get_atom_name,
|
|
58
62
|
pack_get_font_path,
|
|
59
63
|
pack_get_geometry,
|
|
64
|
+
pack_get_keyboard_mapping,
|
|
60
65
|
pack_get_property,
|
|
61
66
|
pack_image,
|
|
62
67
|
pack_image_text,
|
|
@@ -70,10 +75,15 @@ from .protocol import (
|
|
|
70
75
|
pack_poly_fill_raw_arcs,
|
|
71
76
|
pack_poly_fill_raw_rectangles,
|
|
72
77
|
pack_poly_fill_rectangles,
|
|
78
|
+
pack_poly_lines,
|
|
73
79
|
pack_poly_points,
|
|
80
|
+
pack_poly_raw_lines,
|
|
81
|
+
pack_poly_raw_rectangles,
|
|
74
82
|
pack_poly_raw_segments,
|
|
83
|
+
pack_poly_rectangles,
|
|
75
84
|
pack_poly_segments,
|
|
76
85
|
pack_query_extension,
|
|
86
|
+
pack_query_text_extents,
|
|
77
87
|
pack_query_tree,
|
|
78
88
|
pack_reparent_window,
|
|
79
89
|
pack_set_font_path,
|
|
@@ -82,15 +92,16 @@ from .protocol import (
|
|
|
82
92
|
pack_unmap_window,
|
|
83
93
|
unpack_error,
|
|
84
94
|
unpack_event,
|
|
85
|
-
unpack_get_atom_name,
|
|
86
95
|
unpack_get_font_path,
|
|
87
96
|
unpack_get_geometry,
|
|
97
|
+
unpack_get_keyboard_mapping,
|
|
88
98
|
unpack_get_property,
|
|
89
99
|
unpack_intern_atom,
|
|
90
100
|
unpack_list_extensions,
|
|
91
101
|
unpack_list_fonts,
|
|
92
102
|
unpack_list_properties,
|
|
93
103
|
unpack_query_extension,
|
|
104
|
+
unpack_query_text_extents,
|
|
94
105
|
unpack_query_tree,
|
|
95
106
|
unpack_setup,
|
|
96
107
|
unpack_setup_error,
|
|
@@ -99,7 +110,11 @@ from .protocol import (
|
|
|
99
110
|
log = logging.getLogger("aioxlib")
|
|
100
111
|
|
|
101
112
|
|
|
102
|
-
|
|
113
|
+
def unpack_get_atom_name(data, offset=0):
|
|
114
|
+
reply, offset = protocol.unpack_get_atom_name(data, offset)
|
|
115
|
+
return reply["name"], offset
|
|
116
|
+
|
|
117
|
+
|
|
103
118
|
class Extension:
|
|
104
119
|
"""Base class for X protocol extensions."""
|
|
105
120
|
|
|
@@ -115,7 +130,6 @@ class Extension:
|
|
|
115
130
|
self.commands = {}
|
|
116
131
|
|
|
117
132
|
|
|
118
|
-
# --- resource ---
|
|
119
133
|
class Resource:
|
|
120
134
|
"""Base class for server-side resources identified by an XID."""
|
|
121
135
|
|
|
@@ -184,6 +198,10 @@ class Drawable(Resource):
|
|
|
184
198
|
"""Poly fill rectangles."""
|
|
185
199
|
return await self.display.poly_fill_rectangles(self, gc, rectangles)
|
|
186
200
|
|
|
201
|
+
async def poly_rectangles(self, gc, rectangles):
|
|
202
|
+
"""Poly rectangles."""
|
|
203
|
+
return await self.display.poly_rectangles(self, gc, rectangles)
|
|
204
|
+
|
|
187
205
|
async def poly_fill_arcs(self, gc, arcs):
|
|
188
206
|
"""Fill elliptical arcs on this drawable.
|
|
189
207
|
|
|
@@ -200,6 +218,10 @@ class Drawable(Resource):
|
|
|
200
218
|
"""Poly points."""
|
|
201
219
|
return await self.display.poly_points(self, gc, points, mode)
|
|
202
220
|
|
|
221
|
+
async def poly_lines(self, gc, points, mode=CoordinateMode.Origin):
|
|
222
|
+
"""Poly lines."""
|
|
223
|
+
return await self.display.poly_lines(self, gc, points, mode)
|
|
224
|
+
|
|
203
225
|
async def put_text(self, gc, x, y, text, drawable=None):
|
|
204
226
|
"""Put text."""
|
|
205
227
|
drawable = drawable or self
|
|
@@ -240,7 +262,6 @@ class ResourceManager:
|
|
|
240
262
|
return self.base | i
|
|
241
263
|
|
|
242
264
|
|
|
243
|
-
# --- gc ---
|
|
244
265
|
class GC(Resource):
|
|
245
266
|
"""Graphics context resource used by core drawing requests."""
|
|
246
267
|
|
|
@@ -254,6 +275,11 @@ class GC(Resource):
|
|
|
254
275
|
drawable = drawable or self.drawable
|
|
255
276
|
return await self.display.poly_fill_rectangles(drawable, self, rectangles)
|
|
256
277
|
|
|
278
|
+
async def poly_rectangles(self, rectangles, drawable=None):
|
|
279
|
+
"""Poly rectangles."""
|
|
280
|
+
drawable = drawable or self.drawable
|
|
281
|
+
return await self.display.poly_rectangles(drawable, self, rectangles)
|
|
282
|
+
|
|
257
283
|
async def poly_fill_arcs(self, arcs, drawable=None):
|
|
258
284
|
"""Poly fill arcs."""
|
|
259
285
|
if drawable is None:
|
|
@@ -265,11 +291,16 @@ class GC(Resource):
|
|
|
265
291
|
drawable = drawable or self.drawable
|
|
266
292
|
return await self.display.poly_segments(drawable, self, segments)
|
|
267
293
|
|
|
268
|
-
async def poly_points(self, points, mode, drawable=None):
|
|
294
|
+
async def poly_points(self, points, mode=CoordinateMode.Origin, drawable=None):
|
|
269
295
|
"""Poly points."""
|
|
270
296
|
drawable = drawable or self.drawable
|
|
271
297
|
return await self.display.poly_points(drawable, self, points, mode)
|
|
272
298
|
|
|
299
|
+
async def poly_lines(self, points, mode=CoordinateMode.Origin, drawable=None):
|
|
300
|
+
"""Poly points."""
|
|
301
|
+
drawable = drawable or self.drawable
|
|
302
|
+
return await self.display.poly_lines(drawable, self, points, mode)
|
|
303
|
+
|
|
273
304
|
async def put_text(self, x, y, text, drawable=None):
|
|
274
305
|
"""Put text."""
|
|
275
306
|
if drawable is None:
|
|
@@ -277,16 +308,22 @@ class GC(Resource):
|
|
|
277
308
|
payload = pack_image_text(drawable, self, x, y, text)
|
|
278
309
|
self.display.connection.write(payload)
|
|
279
310
|
|
|
311
|
+
async def query_text_extents(self, string, font=None):
|
|
312
|
+
return await self.display.query_text_extents(font or self, string)
|
|
313
|
+
|
|
280
314
|
|
|
281
|
-
# --- window ---
|
|
282
315
|
class Window(Drawable):
|
|
283
316
|
"""X window resource with mapping, properties, and drawing helpers."""
|
|
284
317
|
|
|
318
|
+
def __init__(self, display, wid, depth):
|
|
319
|
+
super().__init__(display, wid)
|
|
320
|
+
self.depth = depth
|
|
321
|
+
|
|
285
322
|
async def create_window(
|
|
286
323
|
self,
|
|
287
324
|
width,
|
|
288
325
|
height,
|
|
289
|
-
depth,
|
|
326
|
+
depth=None,
|
|
290
327
|
x=0,
|
|
291
328
|
y=0,
|
|
292
329
|
border_width=0,
|
|
@@ -299,6 +336,8 @@ class Window(Drawable):
|
|
|
299
336
|
) -> Window:
|
|
300
337
|
"""Create window."""
|
|
301
338
|
wid = self.display.resources.allocate()
|
|
339
|
+
if depth is None:
|
|
340
|
+
depth = self.depth
|
|
302
341
|
payload = pack_create_window(
|
|
303
342
|
depth=depth,
|
|
304
343
|
wid=wid,
|
|
@@ -324,12 +363,16 @@ class Window(Drawable):
|
|
|
324
363
|
wm_protocols = display.WM_PROTOCOLS
|
|
325
364
|
payload += pack_change_property(wid, wm_protocols, Atom.ATOM, 32, protocols, PropMode.Replace)
|
|
326
365
|
self.display.connection.write(payload)
|
|
327
|
-
return Window(self.display, wid)
|
|
366
|
+
return Window(self.display, wid, depth)
|
|
328
367
|
|
|
329
368
|
async def set_name(self, name):
|
|
330
369
|
"""Set name."""
|
|
331
370
|
await self.change_text_property(Atom.WM_NAME, name)
|
|
332
371
|
|
|
372
|
+
async def get_name(self):
|
|
373
|
+
value = await self.get_property(Atom.WM_NAME)
|
|
374
|
+
return value["value"]
|
|
375
|
+
|
|
333
376
|
async def set_motif_hints(self, functions=None, decorations=None, input_mode=None, status=None):
|
|
334
377
|
data = build_motif_wm_hints(
|
|
335
378
|
functions=functions,
|
|
@@ -338,7 +381,7 @@ class Window(Drawable):
|
|
|
338
381
|
status=status,
|
|
339
382
|
)
|
|
340
383
|
atom = await self.display.get_atom(MOTIF_WM_HINTS_ATOM)
|
|
341
|
-
await self.change_property(atom, atom, 32,
|
|
384
|
+
await self.change_property(atom, atom, 32, data)
|
|
342
385
|
|
|
343
386
|
async def set_size_hints(
|
|
344
387
|
self,
|
|
@@ -409,7 +452,58 @@ class Window(Drawable):
|
|
|
409
452
|
Atom.WM_NORMAL_HINTS,
|
|
410
453
|
Atom.WM_SIZE_HINTS,
|
|
411
454
|
32,
|
|
412
|
-
|
|
455
|
+
data,
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
async def set_wm_hints(
|
|
459
|
+
window: Window,
|
|
460
|
+
*,
|
|
461
|
+
input: bool | None = None,
|
|
462
|
+
initial_state: InitialState | int | None = None,
|
|
463
|
+
icon_pixmap: int | None = None,
|
|
464
|
+
icon_window: int | None = None,
|
|
465
|
+
icon_x: int | None = None,
|
|
466
|
+
icon_y: int | None = None,
|
|
467
|
+
icon_mask: int | None = None,
|
|
468
|
+
window_group: int | None = None,
|
|
469
|
+
urgent: bool | None = None,
|
|
470
|
+
) -> None:
|
|
471
|
+
"""Apply ICCCM window-manager hints to *window*.
|
|
472
|
+
|
|
473
|
+
Pass individual fields, or supply a pre-built 9-element list via *data*.
|
|
474
|
+
When *data* is given it takes precedence over the keyword fields.
|
|
475
|
+
|
|
476
|
+
Examples
|
|
477
|
+
--------
|
|
478
|
+
Normal window that accepts keyboard focus::
|
|
479
|
+
|
|
480
|
+
await set_wm_hints(wnd, input=True, initial_state=InitialState.Normal)
|
|
481
|
+
|
|
482
|
+
Start iconic (minimized)::
|
|
483
|
+
|
|
484
|
+
await set_wm_hints(wnd, initial_state=InitialState.Iconic)
|
|
485
|
+
|
|
486
|
+
Mark urgent (attention)::
|
|
487
|
+
|
|
488
|
+
await set_wm_hints(wnd, urgent=True)
|
|
489
|
+
"""
|
|
490
|
+
data = build_wm_hints(
|
|
491
|
+
input=input,
|
|
492
|
+
initial_state=initial_state,
|
|
493
|
+
icon_pixmap=icon_pixmap,
|
|
494
|
+
icon_window=icon_window,
|
|
495
|
+
icon_x=icon_x,
|
|
496
|
+
icon_y=icon_y,
|
|
497
|
+
icon_mask=icon_mask,
|
|
498
|
+
window_group=window_group,
|
|
499
|
+
urgent=urgent,
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
await window.change_property(
|
|
503
|
+
Atom.WM_HINTS,
|
|
504
|
+
Atom.WM_HINTS,
|
|
505
|
+
32,
|
|
506
|
+
data,
|
|
413
507
|
)
|
|
414
508
|
|
|
415
509
|
async def change_text_property(self, property, data, property_type=Atom.STRING, mode=PropMode.Replace):
|
|
@@ -548,7 +642,7 @@ class Screen:
|
|
|
548
642
|
"""Initialize a new Screen instance."""
|
|
549
643
|
self.display = display
|
|
550
644
|
self.info = info
|
|
551
|
-
self.root = Window(display, info["root"])
|
|
645
|
+
self.root = Window(display, info["root"], self.root_depth)
|
|
552
646
|
|
|
553
647
|
def __getattr__(self, name):
|
|
554
648
|
return self.info[name]
|
|
@@ -573,8 +667,6 @@ class Screen:
|
|
|
573
667
|
parent = self.root
|
|
574
668
|
if depth is None:
|
|
575
669
|
depth = self.root_depth
|
|
576
|
-
if background_pixel is None:
|
|
577
|
-
background_pixel = self.black_pixel
|
|
578
670
|
return await parent.create_window(
|
|
579
671
|
x=x,
|
|
580
672
|
y=y,
|
|
@@ -589,8 +681,11 @@ class Screen:
|
|
|
589
681
|
**attrs,
|
|
590
682
|
)
|
|
591
683
|
|
|
684
|
+
async def create_gc(self, drawable=None, **kwargs) -> GC:
|
|
685
|
+
drawable = drawable or self.root
|
|
686
|
+
return await drawable.create_gc(**kwargs)
|
|
687
|
+
|
|
592
688
|
|
|
593
|
-
# --- display ---
|
|
594
689
|
class Pipeline:
|
|
595
690
|
"""Context manager that batches write and write_read requests before flush.
|
|
596
691
|
|
|
@@ -652,7 +747,7 @@ class Display:
|
|
|
652
747
|
self._events = {}
|
|
653
748
|
self._atom_cache = {}
|
|
654
749
|
self._extensions_cache = None
|
|
655
|
-
self.
|
|
750
|
+
self._event_task = None
|
|
656
751
|
self._pipeline = None
|
|
657
752
|
|
|
658
753
|
async def __aenter__(self):
|
|
@@ -669,19 +764,19 @@ class Display:
|
|
|
669
764
|
|
|
670
765
|
def close(self):
|
|
671
766
|
"""Close."""
|
|
672
|
-
if self.
|
|
673
|
-
self.
|
|
767
|
+
if self._event_task:
|
|
768
|
+
self._event_task.cancel()
|
|
674
769
|
self.connection.close()
|
|
675
770
|
|
|
676
771
|
async def aclose(self):
|
|
677
772
|
"""Aclose."""
|
|
678
|
-
if self.
|
|
679
|
-
self.
|
|
773
|
+
if self._event_task:
|
|
774
|
+
self._event_task.cancel()
|
|
680
775
|
try:
|
|
681
|
-
await self.
|
|
776
|
+
await self._event_task
|
|
682
777
|
except asyncio.CancelledError:
|
|
683
778
|
pass
|
|
684
|
-
self.
|
|
779
|
+
self._event_task = None
|
|
685
780
|
await self.connection.aclose()
|
|
686
781
|
|
|
687
782
|
def pipeline(self):
|
|
@@ -732,8 +827,9 @@ class Display:
|
|
|
732
827
|
|
|
733
828
|
async def setup(self):
|
|
734
829
|
"""Perform the X11 connection handshake and populate screens."""
|
|
735
|
-
if self.
|
|
736
|
-
self.
|
|
830
|
+
if self._event_task is None:
|
|
831
|
+
self._event_queue = asyncio.Queue()
|
|
832
|
+
self._event_task = asyncio.create_task(self._loop())
|
|
737
833
|
entry = self.connection.authority()
|
|
738
834
|
payload = pack_setup(entry["name"], entry["data"])
|
|
739
835
|
info = await self.write_read(payload, unpack_setup)
|
|
@@ -748,11 +844,10 @@ class Display:
|
|
|
748
844
|
reply = await self.write_read(payload, unpack_intern_atom)
|
|
749
845
|
return reply["atom"]
|
|
750
846
|
|
|
751
|
-
|
|
847
|
+
def get_atom_name(self, atom):
|
|
752
848
|
"""Return the string name for *atom*."""
|
|
753
849
|
payload = pack_get_atom_name(atom)
|
|
754
|
-
|
|
755
|
-
return reply["name"]
|
|
850
|
+
return self.write_read(payload, unpack_get_atom_name)
|
|
756
851
|
|
|
757
852
|
async def _list_extensions(self):
|
|
758
853
|
payload = pack_list_extensions()
|
|
@@ -902,6 +997,16 @@ class Display:
|
|
|
902
997
|
font = build_font(**kwargs) if name is None else name
|
|
903
998
|
return await self.open_font_name(font)
|
|
904
999
|
|
|
1000
|
+
async def query_text_extents(self, font, string):
|
|
1001
|
+
"""QueryTextExtents — bounding box of *string* in *font* (or GC).
|
|
1002
|
+
|
|
1003
|
+
Returns a dict with draw_direction, font_ascent, font_descent,
|
|
1004
|
+
overall_ascent, overall_descent, overall_width, overall_left,
|
|
1005
|
+
overall_right.
|
|
1006
|
+
"""
|
|
1007
|
+
payload = pack_query_text_extents(font, string)
|
|
1008
|
+
return await self.write_read(payload, unpack_query_text_extents)
|
|
1009
|
+
|
|
905
1010
|
async def tree(self, wnd):
|
|
906
1011
|
"""Tree."""
|
|
907
1012
|
payload = pack_query_tree(wnd)
|
|
@@ -916,6 +1021,14 @@ class Display:
|
|
|
916
1021
|
payload = pack_poly_fill_rectangles(drawable, gc, rectangles)
|
|
917
1022
|
self.write(payload)
|
|
918
1023
|
|
|
1024
|
+
async def poly_rectangles(self, drawable, gc, rectangles):
|
|
1025
|
+
"""Poly rectangles."""
|
|
1026
|
+
if isinstance(rectangles, bytes | bytearray):
|
|
1027
|
+
payload = pack_poly_raw_rectangles(drawable, gc, rectangles)
|
|
1028
|
+
else:
|
|
1029
|
+
payload = pack_poly_rectangles(drawable, gc, rectangles)
|
|
1030
|
+
self.write(payload)
|
|
1031
|
+
|
|
919
1032
|
async def poly_fill_arcs(self, drawable, gc, arcs):
|
|
920
1033
|
"""PolyFillArc — fill elliptical arcs (or full ellipses).
|
|
921
1034
|
|
|
@@ -944,6 +1057,14 @@ class Display:
|
|
|
944
1057
|
payload = pack_poly_points(drawable, gc, points, mode)
|
|
945
1058
|
self.write(payload)
|
|
946
1059
|
|
|
1060
|
+
async def poly_lines(self, drawable, gc, points, mode=CoordinateMode.Origin):
|
|
1061
|
+
"""Poly lines."""
|
|
1062
|
+
if isinstance(points, bytes):
|
|
1063
|
+
payload = pack_poly_raw_lines(drawable, gc, points, mode)
|
|
1064
|
+
else:
|
|
1065
|
+
payload = pack_poly_lines(drawable, gc, points, mode)
|
|
1066
|
+
self.write(payload)
|
|
1067
|
+
|
|
947
1068
|
async def clear_area(self, wnd, x, y, w, h, exposure=False):
|
|
948
1069
|
"""Clear area."""
|
|
949
1070
|
payload = pack_clear_area(wnd, x, y, w, h, exposure)
|
|
@@ -993,6 +1114,12 @@ class Display:
|
|
|
993
1114
|
payload = pack_reparent_window(window, parent, x, y)
|
|
994
1115
|
self.write(payload)
|
|
995
1116
|
|
|
1117
|
+
async def get_keyboard_mapping(self, start=None, count=None):
|
|
1118
|
+
start = start or self.info["min_keycode"]
|
|
1119
|
+
count = count or (self.info["max_keycode"] - start)
|
|
1120
|
+
payload = pack_get_keyboard_mapping(start, count)
|
|
1121
|
+
return await self.write_read(payload, unpack_get_keyboard_mapping)
|
|
1122
|
+
|
|
996
1123
|
def add_listener(self, listener):
|
|
997
1124
|
"""Add listener."""
|
|
998
1125
|
self.listeners.add(listener)
|
|
@@ -1063,7 +1190,12 @@ class Display:
|
|
|
1063
1190
|
# An event
|
|
1064
1191
|
if len(buffer) < 32:
|
|
1065
1192
|
return True, buffer, current_decoder
|
|
1066
|
-
|
|
1193
|
+
try:
|
|
1194
|
+
event, offset = unpack_event(self._events, buffer)
|
|
1195
|
+
except ValueError:
|
|
1196
|
+
log.exception("discarded buffer: %s", buffer)
|
|
1197
|
+
return False, b"", current_decoder
|
|
1198
|
+
|
|
1067
1199
|
for listener in self.listeners:
|
|
1068
1200
|
await listener.put(event)
|
|
1069
1201
|
return False, buffer[offset:], current_decoder
|