pyxtest: fix the vidmode SwitchToModeRequest test

This test was missing SetClientVersion(2) so the reply was a the old 0.x
protocol (and the 36 byte GetModeLine reply). Update so it runs for both
versions now.

Fixes: acbc46e708 ("pyxtest: add tests for the byteswapping patches")
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2213>
This commit is contained in:
Peter Hutterer 2026-05-11 15:50:19 +10:00 committed by Marge Bot
parent 9ad275a8f1
commit 14caf91be2
2 changed files with 161 additions and 38 deletions

View file

@ -19,6 +19,7 @@ VidModeValidateModeLine = 9
VidModeSwitchToMode = 10
VidModeGetViewPort = 11
VidModeSetViewPort = 12
VidModeSetClientVersion = 14
@dataclass
@ -36,6 +37,25 @@ class QueryVersionRequest:
)
@dataclass
class SetClientVersionRequest:
"""VidModeSetClientVersion request (8 bytes)."""
opcode: int
major: int = 2
minor: int = 0
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBH HH",
self.opcode,
VidModeSetClientVersion,
2, # 8 bytes = 2 words
self.major,
self.minor,
)
@dataclass
class GetModeLineRequest:
"""VidModeGetModeLine request."""
@ -134,6 +154,59 @@ class SwitchToModeRequest:
)
@dataclass
class OldSwitchToModeRequest:
"""VidModeSwitchToMode request (v0 format, 36 bytes).
xXF86OldVidModeSwitchToModeReq:
reqType(1) + xf86vidmodeReqType(1) + length(2) +
screen(4) + dotclock(4) +
hdisplay(2) + hsyncstart(2) + hsyncend(2) + htotal(2) +
vdisplay(2) + vsyncstart(2) + vsyncend(2) + vtotal(2) +
flags(4) + privsize(4)
"""
opcode: int
screen: int = 0
dotclock: int = 0
hdisplay: int = 0
hsyncstart: int = 0
hsyncend: int = 0
htotal: int = 0
vdisplay: int = 0
vsyncstart: int = 0
vsyncend: int = 0
vtotal: int = 0
flags: int = 0
privsize: int = 0
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBH" # header (4)
f"I" # screen (4)
f"I" # dotclock (4)
f"HHHH" # hdisplay, hsyncstart, hsyncend, htotal (8)
f"HHHH" # vdisplay, vsyncstart, vsyncend, vtotal (8)
f"I" # flags (4)
f"I", # privsize (4)
self.opcode,
VidModeSwitchToMode,
9, # 36 bytes = 9 words
self.screen,
self.dotclock,
self.hdisplay,
self.hsyncstart,
self.hsyncend,
self.htotal,
self.vdisplay,
self.vsyncstart,
self.vsyncend,
self.vtotal,
self.flags,
self.privsize,
)
@dataclass
class GetAllModeLinesRequest:
"""VidModeGetAllModeLines request."""

View file

@ -13,7 +13,10 @@ from xclient import Extension, X11Error, X11Reply
class TestVidModeSwitchToMode:
@pytest.mark.swapped_client
@pytest.mark.xorg_only
def test_switch_to_mode_fields_swapped(self, xserver, xclient_swapped):
@pytest.mark.parametrize("vidmode_version", [0, 2])
def test_switch_to_mode_fields_swapped(
self, xserver, xclient_swapped, vidmode_version
):
"""
SProcVidModeSwitchToMode previously only swapped stuff->screen.
All mode-line fields (dotclock, hdisplay, ) were left in
@ -40,16 +43,14 @@ class TestVidModeSwitchToMode:
if not isinstance(resp, X11Reply):
pytest.skip("VidMode QueryVersion failed")
if vidmode_version >= 2:
req = vidmode.SetClientVersionRequest(
opcode=ext.opcode,
major=vidmode_version,
)
conn.send_request(req.to_bytes(">"))
# Get the current mode line so we can echo it back.
# xXF86VidModeGetModeLineReply (v2, 52 bytes):
# [8] dotclock(4)
# [12] hdisplay(2) hsyncstart(2)
# [16] hsyncend(2) htotal(2)
# [20] hskew(4)
# [24] vdisplay(2) vsyncstart(2)
# [28] vsyncend(2) vtotal(2)
# [32] flags(4)
# [36] privsize(4)
req = vidmode.GetModeLineRequest(
opcode=ext.opcode,
screen=0,
@ -60,37 +61,86 @@ class TestVidModeSwitchToMode:
if isinstance(resp, X11Error):
pytest.skip("GetModeLine not supported (VidMode not initialised?)")
assert isinstance(resp, X11Reply), f"Expected reply, got {resp}"
assert len(resp.data) >= 40, f"Reply too short: {len(resp.data)}"
dotclock = struct.unpack_from(">I", resp.data, 8)[0]
hdisplay = struct.unpack_from(">H", resp.data, 12)[0]
hsyncstart = struct.unpack_from(">H", resp.data, 14)[0]
hsyncend = struct.unpack_from(">H", resp.data, 16)[0]
htotal = struct.unpack_from(">H", resp.data, 18)[0]
hskew = struct.unpack_from(">I", resp.data, 20)[0]
vdisplay = struct.unpack_from(">H", resp.data, 24)[0]
vsyncstart = struct.unpack_from(">H", resp.data, 26)[0]
vsyncend = struct.unpack_from(">H", resp.data, 28)[0]
vtotal = struct.unpack_from(">H", resp.data, 30)[0]
flags = struct.unpack_from(">I", resp.data, 32)[0]
if vidmode_version >= 2:
# v2 xXF86VidModeGetModeLineReply (52 bytes):
# [8] dotclock(4)
# [12] hdisplay(2) hsyncstart(2)
# [16] hsyncend(2) htotal(2)
# [20] hskew(2) vdisplay(2)
# [24] vsyncstart(2) vsyncend(2)
# [28] vtotal(2) pad2(2)
# [32] flags(4)
# [36..48] reserved(12)
# [48] privsize(4)
assert len(resp.data) >= 52, f"Reply too short: {len(resp.data)}"
dotclock = struct.unpack_from(">I", resp.data, 8)[0]
hdisplay = struct.unpack_from(">H", resp.data, 12)[0]
hsyncstart = struct.unpack_from(">H", resp.data, 14)[0]
hsyncend = struct.unpack_from(">H", resp.data, 16)[0]
htotal = struct.unpack_from(">H", resp.data, 18)[0]
hskew = struct.unpack_from(">H", resp.data, 20)[0]
vdisplay = struct.unpack_from(">H", resp.data, 22)[0]
vsyncstart = struct.unpack_from(">H", resp.data, 24)[0]
vsyncend = struct.unpack_from(">H", resp.data, 26)[0]
vtotal = struct.unpack_from(">H", resp.data, 28)[0]
flags = struct.unpack_from(">I", resp.data, 32)[0]
else:
# v0 xXF86OldVidModeGetModeLineReply (36 bytes, no hskew):
# [8] dotclock(4)
# [12] hdisplay(2) hsyncstart(2)
# [16] hsyncend(2) htotal(2)
# [20] vdisplay(2) vsyncstart(2)
# [24] vsyncend(2) vtotal(2)
# [28] flags(4)
# [32] privsize(4)
assert len(resp.data) >= 36, f"Reply too short: {len(resp.data)}"
dotclock = struct.unpack_from(">I", resp.data, 8)[0]
hdisplay = struct.unpack_from(">H", resp.data, 12)[0]
hsyncstart = struct.unpack_from(">H", resp.data, 14)[0]
hsyncend = struct.unpack_from(">H", resp.data, 16)[0]
htotal = struct.unpack_from(">H", resp.data, 18)[0]
vdisplay = struct.unpack_from(">H", resp.data, 20)[0]
vsyncstart = struct.unpack_from(">H", resp.data, 22)[0]
vsyncend = struct.unpack_from(">H", resp.data, 24)[0]
vtotal = struct.unpack_from(">H", resp.data, 26)[0]
flags = struct.unpack_from(">I", resp.data, 28)[0]
# Switch to the same mode — should succeed.
req = vidmode.SwitchToModeRequest(
opcode=ext.opcode,
screen=0,
dotclock=dotclock,
hdisplay=hdisplay,
hsyncstart=hsyncstart,
hsyncend=hsyncend,
htotal=htotal,
hskew=hskew,
vdisplay=vdisplay,
vsyncstart=vsyncstart,
vsyncend=vsyncend,
vtotal=vtotal,
flags=flags,
privsize=0,
)
# Use the matching request format for the protocol version.
if vidmode_version >= 2:
req = vidmode.SwitchToModeRequest(
opcode=ext.opcode,
screen=0,
dotclock=dotclock,
hdisplay=hdisplay,
hsyncstart=hsyncstart,
hsyncend=hsyncend,
htotal=htotal,
hskew=hskew,
vdisplay=vdisplay,
vsyncstart=vsyncstart,
vsyncend=vsyncend,
vtotal=vtotal,
flags=flags,
privsize=0,
)
else:
req = vidmode.OldSwitchToModeRequest(
opcode=ext.opcode,
screen=0,
dotclock=dotclock,
hdisplay=hdisplay,
hsyncstart=hsyncstart,
hsyncend=hsyncend,
htotal=htotal,
vdisplay=vdisplay,
vsyncstart=vsyncstart,
vsyncend=vsyncend,
vtotal=vtotal,
flags=flags,
privsize=0,
)
conn.send_request(req.to_bytes(">"))
resp = conn.recv_response(timeout=2.0)