xserver/test/pyxtest/proto/present.py
Peter Hutterer 165d2810a0 pyxtest: add test for present notify array byte-swap fix
The test sends a PresentPixmap request with a notify entry from a
byte-swapped client. Without the fix, the window ID in the notify
is not swapped, causing dixLookupWindow to fail with BadWindow.
With the fix, the window ID is correctly interpreted.

See 925edb6c9e ("present: Fix missing byte swaps in sproc_present_pixmap()")

Assisted-by: Claude:claude-claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2212>
2026-05-15 04:01:11 +00:00

178 lines
4.2 KiB
Python

# SPDX-License-Identifier: MIT
#
# Present extension protocol request builders for byteswap testing.
import struct
from dataclasses import dataclass
# Present minor opcodes
PresentQueryVersion = 0
PresentPixmap = 1
PresentNotifyMSC = 2
PresentSelectInput = 3
PresentQueryCapabilities = 4
@dataclass
class QueryVersionRequest:
"""PresentQueryVersion request."""
opcode: int
major: int = 1
minor: int = 2
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBHII",
self.opcode,
PresentQueryVersion,
3,
self.major,
self.minor,
)
@dataclass
class SelectInputRequest:
"""PresentSelectInput request."""
opcode: int
eid: int
window: int
event_mask: int = 0
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBH III",
self.opcode,
PresentSelectInput,
4,
self.eid,
self.window,
self.event_mask,
)
@dataclass
class QueryCapabilitiesRequest:
"""PresentQueryCapabilities request."""
opcode: int
target: int
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBH I",
self.opcode,
PresentQueryCapabilities,
2,
self.target,
)
@dataclass
class PresentNotify:
"""xPresentNotify structure (8 bytes): window(4) + serial(4)."""
window: int
serial: int = 0
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(f"{byte_order}II", self.window, self.serial)
@dataclass
class PixmapRequest:
"""PresentPixmap request.
This is a large request with many fields. All fields are included
to test that byte-swapping handles them all correctly.
"""
opcode: int
window: int
pixmap: int
serial: int = 0
valid: int = 0 # region or None
update: int = 0 # region or None
x_off: int = 0
y_off: int = 0
target_crtc: int = 0
wait_fence: int = 0
idle_fence: int = 0
options: int = 0
target_msc: int = 0
divisor: int = 0
remainder: int = 0
notifies: list[PresentNotify] | None = None
def to_bytes(self, byte_order: str = "<") -> bytes:
notify_data = b""
if self.notifies:
for n in self.notifies:
notify_data += n.to_bytes(byte_order)
base_size = 72 # 18 words
total_size = base_size + len(notify_data)
length = total_size // 4
header = struct.pack(
f"{byte_order}BBH" # header: opcode, sub-opcode, length
f"III" # window, pixmap, serial
f"II" # valid, update
f"hh" # x_off, y_off
f"III" # target_crtc, wait_fence, idle_fence
f"I" # options
f"xxxx" # pad
f"Q" # target_msc (CARD64)
f"Q" # divisor (CARD64)
f"Q", # remainder (CARD64)
self.opcode,
PresentPixmap,
length,
self.window,
self.pixmap,
self.serial,
self.valid,
self.update,
self.x_off,
self.y_off,
self.target_crtc,
self.wait_fence,
self.idle_fence,
self.options,
self.target_msc,
self.divisor,
self.remainder,
)
return header + notify_data
@dataclass
class NotifyMSCRequest:
"""PresentNotifyMSC request."""
opcode: int
window: int
serial: int = 0
target_msc: int = 0
divisor: int = 0
remainder: int = 0
def to_bytes(self, byte_order: str = "<") -> bytes:
return struct.pack(
f"{byte_order}BBH"
f"II" # window, serial
f"xxxx" # pad
f"Q" # target_msc
f"Q" # divisor
f"Q", # remainder
self.opcode,
PresentNotifyMSC,
10, # 40 bytes = 10 words
self.window,
self.serial,
self.target_msc,
self.divisor,
self.remainder,
)