aioxlib 0.7.2__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.
Files changed (43) hide show
  1. {aioxlib-0.7.2 → aioxlib-0.8.0}/PKG-INFO +1 -1
  2. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/__init__.py +1 -1
  3. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/constants.py +36 -0
  4. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/display.py +55 -2
  5. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/protocol.py +106 -0
  6. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib.egg-info/PKG-INFO +1 -1
  7. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_protocol.py +97 -0
  8. {aioxlib-0.7.2 → aioxlib-0.8.0}/LICENSE +0 -0
  9. {aioxlib-0.7.2 → aioxlib-0.8.0}/README.md +0 -0
  10. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/_extensions.py +0 -0
  11. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/api.py +0 -0
  12. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/authority.py +0 -0
  13. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/bigreq.py +0 -0
  14. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/connection.py +0 -0
  15. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/dbe.py +0 -0
  16. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/dri3.py +0 -0
  17. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/glx.py +0 -0
  18. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/present.py +0 -0
  19. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/randr.py +0 -0
  20. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/render.py +0 -0
  21. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/shm.py +0 -0
  22. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib/widgets.py +0 -0
  23. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib.egg-info/SOURCES.txt +0 -0
  24. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib.egg-info/dependency_links.txt +0 -0
  25. {aioxlib-0.7.2 → aioxlib-0.8.0}/aioxlib.egg-info/top_level.txt +0 -0
  26. {aioxlib-0.7.2 → aioxlib-0.8.0}/pyproject.toml +0 -0
  27. {aioxlib-0.7.2 → aioxlib-0.8.0}/setup.cfg +0 -0
  28. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_api.py +0 -0
  29. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_authority.py +0 -0
  30. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_bigreq.py +0 -0
  31. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_connection.py +0 -0
  32. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_constants.py +0 -0
  33. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_dbe.py +0 -0
  34. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_display.py +0 -0
  35. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_dri3.py +0 -0
  36. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_examples.py +0 -0
  37. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_extensions.py +0 -0
  38. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_glx.py +0 -0
  39. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_present.py +0 -0
  40. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_randr.py +0 -0
  41. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_render.py +0 -0
  42. {aioxlib-0.7.2 → aioxlib-0.8.0}/tests/test_shm.py +0 -0
  43. {aioxlib-0.7.2 → 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.7.2
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
@@ -16,7 +16,7 @@ Types and protocol helpers live in submodules::
16
16
  from aioxlib.protocol import pack_create_window
17
17
  """
18
18
 
19
- __version__ = "0.7.2"
19
+ __version__ = "0.8.0"
20
20
 
21
21
  from . import api, constants
22
22
  from .api import * # noqa: F403
@@ -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, list(data))
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
- list(data),
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.7.2
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
@@ -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
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