python-libei 0.5.0__py3-none-any.whl → 0.5.1__py3-none-any.whl
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.
- libei/__init__.py +1 -1
- libei/portal.py +133 -46
- {python_libei-0.5.0.dist-info → python_libei-0.5.1.dist-info}/METADATA +2 -2
- {python_libei-0.5.0.dist-info → python_libei-0.5.1.dist-info}/RECORD +7 -7
- {python_libei-0.5.0.dist-info → python_libei-0.5.1.dist-info}/WHEEL +0 -0
- {python_libei-0.5.0.dist-info → python_libei-0.5.1.dist-info}/licenses/LICENSE +0 -0
- {python_libei-0.5.0.dist-info → python_libei-0.5.1.dist-info}/top_level.txt +0 -0
libei/__init__.py
CHANGED
libei/portal.py
CHANGED
|
@@ -926,6 +926,53 @@ def _input_capture_version(
|
|
|
926
926
|
return int(version)
|
|
927
927
|
|
|
928
928
|
|
|
929
|
+
def _create_input_capture_session_v1(
|
|
930
|
+
connection: Any,
|
|
931
|
+
Gio: Any,
|
|
932
|
+
GLib: Any,
|
|
933
|
+
busname: str,
|
|
934
|
+
types: int,
|
|
935
|
+
timeout: float,
|
|
936
|
+
) -> str:
|
|
937
|
+
"""Create an InputCapture session on a portal that predates v2.
|
|
938
|
+
|
|
939
|
+
v1 has no ``Start`` at all -- that method, like ``CreateSession2``, was
|
|
940
|
+
added in version 2. Here ``CreateSession`` itself carries
|
|
941
|
+
``capabilities`` and raises the consent dialog, and the session is ready
|
|
942
|
+
for ``GetZones`` / ``SetPointerBarriers`` / ``Enable`` the moment its
|
|
943
|
+
``Response`` arrives. ``ConnectToEIS`` is a v1 original, so the rest of
|
|
944
|
+
this class works against such a portal unchanged.
|
|
945
|
+
|
|
946
|
+
Returns the session handle. ``persist_mode`` and ``restore_token`` have
|
|
947
|
+
no v1 equivalent -- both are documented as version 2 additions to
|
|
948
|
+
``Start``, which does not exist here -- so the caller must reject them
|
|
949
|
+
before getting this far rather than have them silently ignored.
|
|
950
|
+
"""
|
|
951
|
+
code, results = _request(
|
|
952
|
+
connection,
|
|
953
|
+
Gio,
|
|
954
|
+
GLib,
|
|
955
|
+
busname,
|
|
956
|
+
_INPUT_CAPTURE,
|
|
957
|
+
"CreateSession",
|
|
958
|
+
"(sa{sv})",
|
|
959
|
+
("",),
|
|
960
|
+
{
|
|
961
|
+
"session_handle_token": GLib.Variant("s", uuid.uuid4().hex),
|
|
962
|
+
"capabilities": GLib.Variant("u", int(types)),
|
|
963
|
+
},
|
|
964
|
+
timeout,
|
|
965
|
+
)
|
|
966
|
+
if code != 0:
|
|
967
|
+
raise PortalDeniedError(
|
|
968
|
+
"CreateSession", "the user declined the input-capture consent dialog"
|
|
969
|
+
)
|
|
970
|
+
session_handle = results.get("session_handle")
|
|
971
|
+
if not isinstance(session_handle, str):
|
|
972
|
+
raise PortalError("CreateSession returned no session_handle")
|
|
973
|
+
return session_handle
|
|
974
|
+
|
|
975
|
+
|
|
929
976
|
def _wait_for_signal(
|
|
930
977
|
connection: Any,
|
|
931
978
|
Gio: Any,
|
|
@@ -1392,11 +1439,18 @@ class InputCaptureSession:
|
|
|
1392
1439
|
Blocks until ``CreateSession2`` -> ``Start`` -> ``ConnectToEIS``
|
|
1393
1440
|
resolves, prompting the user for consent along the way unless
|
|
1394
1441
|
``restore_token`` lets the portal skip that. Raises
|
|
1395
|
-
:class:`
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1442
|
+
:class:`PortalDeniedError` if consent is declined, and
|
|
1443
|
+
:class:`PortalTimeoutError` if any one round trip exceeds ``timeout``
|
|
1444
|
+
seconds.
|
|
1445
|
+
|
|
1446
|
+
A portal older than v2 has neither ``CreateSession2`` nor ``Start``,
|
|
1447
|
+
and is negotiated through the deprecated v1 ``CreateSession``
|
|
1448
|
+
instead -- one call that carries ``capabilities`` and raises the
|
|
1449
|
+
consent dialog itself. Everything after negotiation is identical;
|
|
1450
|
+
``ConnectToEIS`` is a v1 original. The one thing v1 cannot do is
|
|
1451
|
+
persist: ``persist_mode`` and ``restore_token`` were added to
|
|
1452
|
+
``Start``, so passing either against such a portal raises
|
|
1453
|
+
:class:`PortalVersionError` rather than being quietly ignored.
|
|
1400
1454
|
|
|
1401
1455
|
Returns before anything is actually captured: :meth:`set_pointer_barriers`
|
|
1402
1456
|
and :meth:`enable` still have to be called, and even then nothing
|
|
@@ -1435,62 +1489,95 @@ class InputCaptureSession:
|
|
|
1435
1489
|
raise PortalError(f"cannot reach the session bus: {exc}") from exc
|
|
1436
1490
|
|
|
1437
1491
|
version = _input_capture_version(connection, Gio, GLib, busname, timeout)
|
|
1438
|
-
|
|
1492
|
+
# A version below 2 is not a portal to give up on -- it is a portal
|
|
1493
|
+
# that speaks the older half of the same interface. Only
|
|
1494
|
+
# `CreateSession2` and `Start` are version 2 additions; `GetZones`,
|
|
1495
|
+
# `SetPointerBarriers`, `Enable`, `Disable`, `Release` and, crucially,
|
|
1496
|
+
# `ConnectToEIS` are all v1 originals, so everything this class does
|
|
1497
|
+
# after negotiation works either way and only session creation forks.
|
|
1498
|
+
#
|
|
1499
|
+
# This is not hypothetical. xdg-desktop-portal-gnome 50 reports
|
|
1500
|
+
# version 0 -- it registers the full impl interface and never sets the
|
|
1501
|
+
# property -- and calling `CreateSession2` against it fails with
|
|
1502
|
+
# `UnknownMethod`, while v1 `CreateSession` is dispatched normally.
|
|
1503
|
+
# Note that its introspection XML advertises `CreateSession2` anyway:
|
|
1504
|
+
# that XML is static, so it says nothing about what the frontend will
|
|
1505
|
+
# actually dispatch. The `version` property is the only usable signal,
|
|
1506
|
+
# which is why it is read first and believed.
|
|
1507
|
+
legacy = version < _MIN_INPUT_CAPTURE_VERSION
|
|
1508
|
+
|
|
1509
|
+
if legacy and (persist_mode != PersistMode.NONE or restore_token is not None):
|
|
1439
1510
|
raise PortalVersionError(
|
|
1440
|
-
f"InputCapture version {version}
|
|
1441
|
-
f"
|
|
1511
|
+
f"InputCapture version {version} has no Start method, and "
|
|
1512
|
+
f"persist_mode/restore_token are version "
|
|
1513
|
+
f"{_MIN_INPUT_CAPTURE_VERSION} additions to it -- this portal "
|
|
1514
|
+
f"cannot persist a session. Retry with persist_mode=NONE and "
|
|
1515
|
+
f"no restore_token to negotiate a one-shot session."
|
|
1442
1516
|
)
|
|
1443
1517
|
|
|
1444
1518
|
if capabilities == DeviceType.ALL_DEVICES:
|
|
1445
1519
|
types = _ALL_DEVICE_TYPES
|
|
1446
1520
|
else:
|
|
1447
1521
|
types = capabilities
|
|
1448
|
-
reply = _call_sync(
|
|
1449
|
-
connection,
|
|
1450
|
-
Gio,
|
|
1451
|
-
GLib,
|
|
1452
|
-
busname,
|
|
1453
|
-
_OBJECT_PATH,
|
|
1454
|
-
_INPUT_CAPTURE,
|
|
1455
|
-
"CreateSession2",
|
|
1456
|
-
GLib.Variant(
|
|
1457
|
-
"(a{sv})",
|
|
1458
|
-
({"session_handle_token": GLib.Variant("s", uuid.uuid4().hex)},),
|
|
1459
|
-
),
|
|
1460
|
-
None,
|
|
1461
|
-
int(timeout * 1000),
|
|
1462
|
-
)
|
|
1463
|
-
(results,) = reply.unpack()
|
|
1464
|
-
session_handle = results.get("session_handle")
|
|
1465
|
-
if not isinstance(session_handle, str):
|
|
1466
|
-
raise PortalError("CreateSession2 returned no session_handle")
|
|
1467
1522
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
options["persist_mode"] = GLib.Variant("u", int(persist_mode))
|
|
1475
|
-
if restore_token is not None:
|
|
1476
|
-
options["restore_token"] = GLib.Variant("s", restore_token)
|
|
1477
|
-
code, start_results = _request(
|
|
1523
|
+
if legacy:
|
|
1524
|
+
session_handle = _create_input_capture_session_v1(
|
|
1525
|
+
connection, Gio, GLib, busname, int(types), timeout
|
|
1526
|
+
)
|
|
1527
|
+
else:
|
|
1528
|
+
reply = _call_sync(
|
|
1478
1529
|
connection,
|
|
1479
1530
|
Gio,
|
|
1480
1531
|
GLib,
|
|
1481
1532
|
busname,
|
|
1533
|
+
_OBJECT_PATH,
|
|
1482
1534
|
_INPUT_CAPTURE,
|
|
1483
|
-
"
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1535
|
+
"CreateSession2",
|
|
1536
|
+
GLib.Variant(
|
|
1537
|
+
"(a{sv})",
|
|
1538
|
+
({"session_handle_token": GLib.Variant("s", uuid.uuid4().hex)},),
|
|
1539
|
+
),
|
|
1540
|
+
None,
|
|
1541
|
+
int(timeout * 1000),
|
|
1488
1542
|
)
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1543
|
+
(results,) = reply.unpack()
|
|
1544
|
+
session_handle = results.get("session_handle")
|
|
1545
|
+
if not isinstance(session_handle, str):
|
|
1546
|
+
raise PortalError("CreateSession2 returned no session_handle")
|
|
1547
|
+
|
|
1548
|
+
# Past this point a session exists inside xdg-desktop-portal, and
|
|
1549
|
+
# nothing else can close it -- see RemoteDesktopSession.negotiate's
|
|
1550
|
+
# identical reasoning, which this mirrors line for line.
|
|
1551
|
+
try:
|
|
1552
|
+
# v1 asked for consent and capabilities in CreateSession itself,
|
|
1553
|
+
# and has no Start to call; it can therefore never issue a
|
|
1554
|
+
# restore token either.
|
|
1555
|
+
new_restore_token = None
|
|
1556
|
+
if not legacy:
|
|
1557
|
+
options: dict[str, Any] = {
|
|
1558
|
+
"capabilities": GLib.Variant("u", int(types))
|
|
1559
|
+
}
|
|
1560
|
+
if persist_mode != PersistMode.NONE:
|
|
1561
|
+
options["persist_mode"] = GLib.Variant("u", int(persist_mode))
|
|
1562
|
+
if restore_token is not None:
|
|
1563
|
+
options["restore_token"] = GLib.Variant("s", restore_token)
|
|
1564
|
+
code, start_results = _request(
|
|
1565
|
+
connection,
|
|
1566
|
+
Gio,
|
|
1567
|
+
GLib,
|
|
1568
|
+
busname,
|
|
1569
|
+
_INPUT_CAPTURE,
|
|
1570
|
+
"Start",
|
|
1571
|
+
"(osa{sv})",
|
|
1572
|
+
(session_handle, ""),
|
|
1573
|
+
options,
|
|
1574
|
+
timeout,
|
|
1492
1575
|
)
|
|
1493
|
-
|
|
1576
|
+
if code != 0:
|
|
1577
|
+
raise PortalDeniedError(
|
|
1578
|
+
"Start", "the user declined the input-capture consent dialog"
|
|
1579
|
+
)
|
|
1580
|
+
new_restore_token = start_results.get("restore_token")
|
|
1494
1581
|
|
|
1495
1582
|
eis_fd = _call_for_fd(
|
|
1496
1583
|
connection,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-libei
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Inject and receive input on Wayland from Python: ctypes bindings for libei, libeis and liboeffis
|
|
5
5
|
Author: Dennis K. Paulsen
|
|
6
6
|
License-Expression: MIT
|
|
@@ -156,7 +156,7 @@ and why, is in
|
|
|
156
156
|
|
|
157
157
|
## Status
|
|
158
158
|
|
|
159
|
-
Beta (`0.5.
|
|
159
|
+
Beta (`0.5.1`), published on [PyPI](https://pypi.org/project/python-libei/)
|
|
160
160
|
since `0.1.0`, and **the API is not frozen** — expect renames before 1.0.
|
|
161
161
|
|
|
162
162
|
The injection path is exercised end to end against the real libraries by the
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
libei/__init__.py,sha256=
|
|
1
|
+
libei/__init__.py,sha256=ZknUZWRNN4JfCH08NGpbBhqr_e2YZjHnk8B1aXe2J9Y,1858
|
|
2
2
|
libei/_cobject.py,sha256=msrbviABSWjc5fKsXHSCg7nQ0Y4Etcq_Dkh0fblW-sY,12845
|
|
3
3
|
libei/ei.py,sha256=Da3ezXnFPXtejlcJFH8bcE5f4pxKZXXqb6ltCh2zAdE,46704
|
|
4
4
|
libei/eis.py,sha256=aYWOCN1NlRchcWd6NjIUi1eYMFWJbp0UHMcQFEJ0ii4,43642
|
|
5
5
|
libei/oeffis.py,sha256=UcnDwLErFxB0xuktNpIzAK01ylpl6ZrmaGnWiUOcFOo,9302
|
|
6
|
-
libei/portal.py,sha256
|
|
6
|
+
libei/portal.py,sha256=LGRINrYQ-x46i0pzGOzpM6ZT3xek_AoExNIgR2BZRB8,64498
|
|
7
7
|
libei/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
libei/_capi/__init__.py,sha256=3VxixYYlr_ZcuiK0GwrCpbE3VvEv_O990mJzdIJ8i74,209
|
|
9
9
|
libei/_capi/libei.py,sha256=gpp42bhqPonhVD2zmFWCl4rdk_lm4XvD_7W2Rw5RsuI,11308
|
|
10
10
|
libei/_capi/libeis.py,sha256=jQR0Z0YN9qa71mAcSJ__-UaoF8PsVsBs8OXwjfqstFk,13080
|
|
11
11
|
libei/_capi/liboeffis.py,sha256=V8jdmJm3qOQUzzNiCAXt4Jr2JY11Y4-w6NIfIxbxGI4,1218
|
|
12
12
|
libei/_capi/loader.py,sha256=k7fb_Nz0fg5QkuLJ_duKXj8bESSktLQ2ZyS5LNQ5v2I,4689
|
|
13
|
-
python_libei-0.5.
|
|
14
|
-
python_libei-0.5.
|
|
15
|
-
python_libei-0.5.
|
|
16
|
-
python_libei-0.5.
|
|
17
|
-
python_libei-0.5.
|
|
13
|
+
python_libei-0.5.1.dist-info/licenses/LICENSE,sha256=l6xbMU6Y-JZDzmBciBj-J5t6h6jNg_Bcyp4bHxDepqU,1074
|
|
14
|
+
python_libei-0.5.1.dist-info/METADATA,sha256=Bg1meYzLmMAp9HqeMWbU4SzZZOurlSGzIR49ZmoJNgo,20475
|
|
15
|
+
python_libei-0.5.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
16
|
+
python_libei-0.5.1.dist-info/top_level.txt,sha256=_DQXzGjDsUBENI_cNkiOxPB4xi8coCbQS1lq18FMudQ,6
|
|
17
|
+
python_libei-0.5.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|