What is the CARD variable type in XRANDR?

83 Views Asked by At

Edit2: Just to make it clear, integers are what I originally entered into the program. My original code, before I started testing anything, was this:

import struct
from Xlib import X, display, Xutil
from Xlib.ext import randr

d = display.Display(':0')
screen = 0
info = d.screen(screen)
window = info.root
randr.set_screen_size(window, 2000, 2000)

and it gave me the same struct.error: required argument is not an integer. I have also done randr.set_screen_size(window,int(2000),int(2000)), just to make sure that I was entering integers, and that has also returned the same struct.error.

Edit1: From what I understand it seems that CARD is an unsigned integer type, and CARD16 is an unsigned 16 bit short. According to Roland Smith's answer, is seems that the way this is handled in the python Xlib library is through struct. As such I checked that I was passing integers to the argument, and I was. I also tried making them into unsigned 16 bit integers ahead of time, but that did not work. This is my current code:

import struct
from Xlib import X, display, Xutil
from Xlib.ext import randr

d = display.Display(':0')
screen = 0
info = d.screen(screen)
window = info.root
short16bit = struct.pack("H", int(2000))
randr.set_screen_size(window, short16bit, short16bit)

and this is the full error:

Traceback (most recent call last):
  File "/home/deishuukaikirpi/XRANDRTesting.py", line 59, in <module>
    randr.set_screen_size(window, short16bit, short16bit)
  File "/home/deishuukaikirpi/.local/lib/python3.9/site-packages/Xlib/ext/randr.py", line 387, in set_screen_size
    return SetScreenSize(
  File "/home/deishuukaikirpi/.local/lib/python3.9/site-packages/Xlib/protocol/rq.py", line 1347, in __init__
    self._binary = self._request.to_binary(*args, **keys)
  File "/home/deishuukaikirpi/.local/lib/python3.9/site-packages/Xlib/protocol/rq.py", line 1069, in to_binary
    static_part = struct.pack(self.static_codes, *pack_items)
struct.error: required argument is not an integer

I still get the same struct.error: required argument is not an integer error. Interestingly enough, if I put a large enough integer into width or height I instead get the error struct.error: ushort format requires 0 <= number <= (0x7fff * 2 + 1), which does seem to imply that this is an unsigned short.

Original: I am working on a program that lets me manipulate displays through Python-Xlib. I got everything working and figured everything out until I hit randr.set_screen_size(). It has three necessary arguments - self, which takes a window variable, as well as length and width which both take CARD16 variables respectively. The documentation that I found of XRANDR which I have been using, found here, outlines CARD32, CARD16, and CARD8 as variable types but does not explain what they are nor how to produce them.

I thought that they were originally just special integer variables, and as such entered integers. I got the error "struct.error: required argument is not an integer." I then tried putting in a string as well as binary via the bin function and both of them returned the same error as when I entered an integer.

2

There are 2 best solutions below

0
Lazuli On BEST ANSWER

Okay, I found the problem. set_screen_size actually takes 5 parameters: self, which takes a window object, width and height which each take CARD16 objects, and finally width_in_millimeters and height_in_millimeters which take CARD32 objects. I didn't think that width_in_millimeters or height_in_millimeters mattered because they are set to None automatically in the Xlib code, but apparently it does matter. This still hasn't gotten the program working, because now, instead of returning an error, it just isn't doing what its supposed to do, but I'm going to start a new question for that.

So to answer the title question: CARD is short for Cardinal number. Cardinal numbers are non-negative integers. CARD8, CARD16, and CARD32, in XRANDR, are an unsigned character, an unsigned short, and an unsigned long, respectively. Python does not natively support these, but they can be recreated using the struct library.

0
Roland Smith On

Looking at xrandr.py, we see

from Xlib.protocol import rq

class SetScreenSize(rq.Request):
    _request = rq.Struct(
        rq.Card8('opcode'),
        rq.Opcode(7),
        rq.RequestLength(),
        rq.Window('window'),
        rq.Card16('width'),
        rq.Card16('height'),
        rq.Card32('width_in_millimeters'),
        rq.Card32('height_in_millimeters'),
        )

def set_screen_size(self, width, height, width_in_millimeters=None, height_in_millimeters=None):
    return SetScreenSize(
        display=self.display,
        opcode=self.display.get_extension_major(extname),
        window=self,
        width=width,
        height=height,
        width_in_millimeters=width_in_millimeters,
        height_in_millimeters=height_in_millimeters,
        )

Looking at protocol/rq.py, we see:

class Card16(ValueField):
    structcode = 'H'
    structvalues = 1

class Card32(ValueField):
    structcode = 'L'
    structvalues = 1

So these cards seem to use the standard library's struct module.

Looking at the documentation of the standard library's struct module, H is an unsigned short and L is an unsigned long.

Look closely at what your error message is saying;

struct.error: required argument is not an integer.

That means that the argument in question cannot be converted to an integer. Are you perhaps using floating point numbers or strings? Because the struct module won't convert those;

In [1]: import struct

In [2]: struct.pack("H", 32)
Out[2]: b' \x00'

In [3]: struct.pack("L", 327)
Out[3]: b'G\x01\x00\x00\x00\x00\x00\x00'

In [4]: struct.pack("H", 32.0)
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
Cell In[4], line 1
----> 1 struct.pack("H", 32.0)

error: required argument is not an integer

In [5]: struct.pack("H", "32")
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
Cell In[5], line 1
----> 1 struct.pack("H", "32")

error: required argument is not an integer

Note how this results in the exact error message you are seeing.

If the supplied value is an integer but outside the range, you would get a different error;

---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
Cell In[6], line 1
----> 1 struct.pack("H", 2**16+1)

error: ushort format requires 0 <= number <= 0xffff

Try explicitly converting the value to an integer before passing it to the CardXX class. That works with floats and strings:

In [7]: struct.pack("H", int(32.0))
Out[7]: b' \x00'

In [8]: struct.pack("H", int("32"))
Out[8]: b' \x00'