-
Notifications
You must be signed in to change notification settings - Fork 112
Description
Bug Report: python-xlib fails to retrieve standard X server Visual/Depth information
Description:
I am encountering a persistent and unusual issue where python-xlib (both 0.33 and 0.29) on Void Linux (using Python 3.13 and Python 3.11) is unable to properly retrieve and expose X server visual and depth information, leading to AttributeError on expected properties and an inability to find the default visual in screen.allowed_depths.
My X server is functioning normally and reports standard visual information via xdpyinfo.
Environment:
- Operating System: Void Linux (x86_64)
- Python Version (tested): Python 3.13.0) and Python 3.11.12_2
python-xlibVersion (tested): 0.33 and 0.29- X Server: "Xorg"
- Desktop Environment/Window Manager: Openbox
Steps to Reproduce:
- Create a Python virtual environment (tested with both Python 3.13 and Python 3.11).
- Install
python-xlib==0.33(then later tried 0.29) into the environment:
pip install python-xlib==0.33(thenpip install python-xlib==0.29) - Ran Python script
test_xlib.pyto check basicscreenproperties. - Ran Python script
center_dot.pywhich attempts to find and use the default visual.
Expected Behavior:
The python-xlib library should successfully access properties like screen.default_visual, screen.default_depth, root.get_geometry().visual, and visual_obj.id within screen.allowed_depths. It should be able to identify and use the default visual (0x20 / 32) and depth (24) reported by xdpyinfo.
Actual Behavior / Error Messages:
1. Output from test_xlib.py (with python-xlib 0.33):
Successfully connected to X server.
Screen width: 1920
Screen height: 1080
Root visual ID (screen.root_visual): 32
Root depth (screen.root_depth): 24
AttributeError trying to get screen properties: get_visual_from_id
This indicates a deep issue with python-xlib's interaction with your X server.
Disconnected from X server.
2. Output from center_dot.py (after attempts with getattr workaround, python-xlib 0.33, Python 3.13):
CRITICAL: Could not find a matching Visual object for ID 32 and depth 24. Exiting.
(Note: This occurred after the AttributeError: id was bypassed by getattr.)
3. Output from center_dot.py (with python-xlib 0.29, Python 3.11):
Warning: 'screen.default_visual' or 'screen.default_depth' not found directly. Falling back to root geometry.
Traceback (most recent call last):
File "/home/XXX/pyxdg_env_py311/lib/python3.11/site-packages/Xlib/protocol/rq.py", line 1294, in getattr
return self._data[attr]
KeyError: 'default_visual'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/XXXX/python_scripts/center_dot.py", line 34, in create_centered_dot_overlay
selected_visual = screen.default_visual
^^^^^^^^^^^^^^^^^^^^^
File "/home/XXXX/pyxdg_env_py311/lib/python3.11/site-packages/Xlib/protocol/rq.py", line 1298, in getattr
raise AttributeError(attr)
AttributeError: default_visual
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/XXXX/pyxdg_env_py311/lib/python3.11/site-packages/Xlib/protocol/rq.py", line 1294, in getattr
return self._data[attr]
~~~~~~~~~~^^^^^^
KeyError: 'visual'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/XXXX/python_scripts/center_dot.py", line 144, in <module>
create_centered_dot_overlay()
File "/home/XXXX/python_scripts/center_dot.py", line 41, in create_centered_dot_overlay
if isinstance(geometry.visual, int):
^^^^^^^^^^^^^^^
File "/home/XXXX/pyxdg_env_py311/lib/python3.11/site-packages/Xlib/protocol/rq.py", line 1298, in getattr
raise AttributeError(attr)
AttributeError: visual
**4. Output from `xdpyinfo | grep -E "visual|depths"` (showing correct X server data):**
depths (7): 24, 1, 4, 8, 15, 16, 32
number of visuals: 156
default visual id: 0x20
visual:
visual id: 0x20
**5. Python Script `test_xlib.py` (as provided earlier):**
```python
# ~/python_scripts/test_xlib.py
#!/usr/bin/env python3
import Xlib.display
import Xlib.X
try:
display = Xlib.display.Display()
screen = display.screen()
root = screen.root
print("Successfully connected to X server.")
print(f"Screen width: {root.get_geometry().width}")
print(f"Screen height: {root.get_geometry().height}")
try:
print(f"Root visual ID (screen.root_visual): {screen.root_visual}")
print(f"Root depth (screen.root_depth): {screen.root_depth}")
# This is the line that failed last:
test_visual_object = screen.get_visual_from_id(screen.root_visual)
print(f"Got visual object from ID. Its ID is: {test_visual_object.id}")
except AttributeError as e:
print(f"AttributeError trying to get screen properties: {e}")
print("This indicates a deep issue with python-xlib's interaction with your X server.")
except Exception as e:
print(f"An unexpected error occurred while getting screen properties: {e}")
display.close()
print("Disconnected from X server.")
except Xlib.error.DisplayNameError:
print("ERROR: Cannot open display. Is X server running and DISPLAY environment variable set?")
except Exception as e:
print(f"An unexpected error occurred during Xlib initialization: {e}")
# ~/python_scripts/center_dot.py
#!/usr/bin/env python3
import Xlib.display
import Xlib.X
import Xlib.protocol.event
from Xlib.ext import xfixes
import time
def create_centered_dot_overlay():
display = Xlib.display.Display()
screen = display.screen()
root = screen.root
screen_width = root.get_geometry().width
screen_height = root.get_geometry().height
center_x = screen_width // 2
center_y = screen_height // 2
TARGET_VISUAL_ID_DEC = 32
TARGET_DEPTH = 24
selected_visual = None
found_depth = None
print(f"Searching for visual ID {TARGET_VISUAL_ID_DEC} with depth {TARGET_DEPTH}...")
for depth_info in screen.allowed_depths:
print(f" Checking depth: {depth_info.depth}")
if depth_info.depth == TARGET_DEPTH:
for visual_obj in depth_info.visuals:
visual_id_val = getattr(visual_obj, 'id', None)
if visual_id_val is not None and visual_id_val == TARGET_VISUAL_ID_DEC:
selected_visual = visual_obj
found_depth = depth_info.depth
print(f" --> Found matching visual: ID {selected_visual.id}, Depth {found_depth}")
break
if selected_visual:
break
if selected_visual is None:
print(f"CRITICAL: Could not find a matching Visual object for ID {TARGET_VISUAL_ID_DEC} and depth {TARGET_DEPTH} within screen.allowed_depths. Exiting.")
print("This indicates a severe incompatibility or issue with your python-xlib installation or X server configuration.")
display.close()
exit(1)
print(f"Using visual ID: {selected_visual.id} with depth: {found_depth}")
print("Transparency might not work without a compositing manager (Picom/Compton) and a suitable visual.")
window = root.create_window(
0, 0, screen_width, screen_height, 0,
found_depth,
Xlib.X.InputOutput,
selected_visual,
Xlib.X.CWBackPixel | Xlib.X.CWEventMask | Xlib.X.CWOverrideRedirect | Xlib.X.CWColormap,
{
'background_pixel': 0,
'event_mask': Xlib.X.ExposureMask,
'override_redirect': True,
'colormap': display.create_colormap(root, selected_visual, Xlib.X.AllocNone)
}
)
NET_WM_STATE = display.intern_atom('_NET_WM_STATE')
_NET_WM_STATE_ABOVE = display.intern_atom('_NET_WM_STATE_ABOVE')
window.change_property(
Xlib.X.ChangePropertyModeReplace,
NET_WM_STATE,
Xlib.display.None_,
32,
[_NET_WM_STATE_ABOVE]
)
event = Xlib.protocol.event.ClientMessage(
window=window,
client_type=NET_WM_STATE,
data=(32, (_NET_WM_STATE_ABOVE, 1, 0, 0, 0))
)
root.send_event(event, Xlib.X.SubstructureNotifyMask | Xlib.X.SubstructureRedirectMask)
empty_region = xfixes.create_region(display)
xfixes.set_window_shape_region(display, window.id, Xlib.X.ShapeInput, 0, 0, empty_region)
empty_region.free()
window.map_window()
display.sync()
dot_color = screen.black_pixel
gc = window.create_gc(
foreground=dot_color,
function=Xlib.X.GXcopy
)
try:
while True:
event = display.next_event()
if event.type == Xlib.X.Expose:
dot_size = 3
window.fill_arc(gc, center_x - dot_size, center_y - dot_size,
dot_size * 2, dot_size * 2, 0, 360 * 64)
display.flush()
time.sleep(0.01)
except KeyboardInterrupt:
print("\nExiting dot overlay.")
finally:
gc.free()
window.destroy()
display.close()
if __name__ == "__main__":
create_centered_dot_overlay()
xdpyinfo shows correct X server data.
attempted different python-xlib versions and Python interpreter versions without success.
issue isolated to python-xlib's internal handling of X server responses.