1
0

xrandrl 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #!/usr/bin/env python3
  2. # PYTHON_ARGCOMPLETE_OK
  3. """
  4. https://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c
  5. """
  6. import ctypes
  7. X_Time = ctypes.c_ulong
  8. """
  9. #ifndef _XTYPEDEF_XID
  10. # define _XTYPEDEF_XID
  11. # ifndef _XSERVER64
  12. typedef unsigned long XID;
  13. # else
  14. typedef CARD32 XID;
  15. # endif
  16. #endif
  17. """
  18. X_XID = ctypes.c_ulong
  19. """
  20. typedef XID RROutput;
  21. """
  22. X_RROutput = X_XID
  23. """
  24. typedef XID RRCrtc;
  25. """
  26. X_RRCrtc = X_XID
  27. """ /usr/include/X11/extensions/Xrandr.h
  28. typedef XID RRMode;
  29. """
  30. X_RRMode = X_XID
  31. """ /usr/include/X11/extensions/randr.h
  32. #define RR_Connected 0
  33. """
  34. X_RR_Connected = 0
  35. """ /usr/include/X11/extensions/randr.h
  36. typedef unsigned short Connection;
  37. """
  38. X_Connection = ctypes.c_ushort
  39. """ /usr/include/X11/extensions/randr.h
  40. typedef unsigned short SubpixelOrder;
  41. """
  42. X_SubpixelOrder = ctypes.c_ushort
  43. """ /usr/include/X11/Xdefs.h
  44. #ifndef _XTYPEDEF_ATOM
  45. # define _XTYPEDEF_ATOM
  46. # ifndef _XSERVER64
  47. typedef unsigned long Atom;
  48. # else
  49. typedef CARD32 Atom;
  50. # endif
  51. #endif
  52. """
  53. X_Atom = ctypes.c_ulong
  54. class X_XRRScreenResources(ctypes.Structure):
  55. """ /usr/include/X11/extensions/Xrandr.h
  56. typedef struct _XRRScreenResources {
  57. Time timestamp;
  58. Time configTimestamp;
  59. int ncrtc;
  60. RRCrtc *crtcs;
  61. int noutput;
  62. RROutput *outputs;
  63. int nmode;
  64. XRRModeInfo *modes;
  65. } XRRScreenResources;
  66. """
  67. _fields_ = [
  68. ('timestamp', X_Time),
  69. ('configTimestamp', X_Time),
  70. ('ncrtc', ctypes.c_int),
  71. ('crtcs', ctypes.POINTER(X_RRCrtc)),
  72. ('noutput', ctypes.c_int),
  73. ('outputs', ctypes.POINTER(X_RROutput)),
  74. ('nmode', ctypes.c_int),
  75. ('modes', ctypes.c_void_p), # ctypes.POINTER(XRRModeInfo)
  76. ]
  77. class X_XRROutputInfo(ctypes.Structure):
  78. """
  79. typedef struct _XRROutputInfo {
  80. Time timestamp;
  81. RRCrtc crtc;
  82. char *name;
  83. int nameLen;
  84. unsigned long mm_width;
  85. unsigned long mm_height;
  86. Connection connection;
  87. SubpixelOrder subpixel_order;
  88. int ncrtc;
  89. RRCrtc *crtcs;
  90. int nclone;
  91. RROutput *clones;
  92. int nmode;
  93. int npreferred;
  94. RRMode *modes;
  95. } XRROutputInfo;
  96. """
  97. _fields_ = [
  98. ('timestamp', X_Time),
  99. ('crtc', X_RRCrtc),
  100. ('name', ctypes.c_char_p),
  101. ('nameLen', ctypes.c_int),
  102. ('mm_width', ctypes.c_ulong),
  103. ('mm_height', ctypes.c_ulong),
  104. ('connection', X_Connection),
  105. ('subpixel_order', X_SubpixelOrder),
  106. ('ncrtc', ctypes.c_int),
  107. ('crtcs', ctypes.POINTER(X_RRCrtc)),
  108. ('nclone', ctypes.c_int),
  109. ('clones', ctypes.POINTER(X_RROutput)),
  110. ('nmode', ctypes.c_int),
  111. ('npreferred', ctypes.c_int),
  112. ('modes', ctypes.POINTER(X_RRMode)),
  113. ]
  114. X11 = ctypes.cdll.LoadLibrary("libX11.so")
  115. Xrandr = ctypes.cdll.LoadLibrary("libXrandr.so")
  116. Xrandr.XRRGetScreenResourcesCurrent.restype = \
  117. ctypes.POINTER(X_XRRScreenResources)
  118. """
  119. XRROutputInfo *
  120. XRRGetOutputInfo (Display *dpy, XRRScreenResources *resources, RROutput output);
  121. """
  122. Xrandr.XRRGetOutputInfo.restype = ctypes.POINTER(X_XRROutputInfo)
  123. Xrandr.XRRListOutputProperties.restype = ctypes.POINTER(X_Atom)
  124. class RandrScreenResources:
  125. def __init__(self, xdisplay, window):
  126. self._xdisplay = xdisplay
  127. self._p = Xrandr.XRRGetScreenResourcesCurrent(xdisplay, window)
  128. def __del__(self):
  129. X11.XFree(self._p)
  130. @property
  131. def outputs(self):
  132. return [self._p.contents.outputs[o] for o in range(self._p.contents.noutput)]
  133. def get_output_infos(self):
  134. return [RandrOutputInfo(self, o) for o in self.outputs]
  135. class RandrOutputInfo:
  136. def __init__(self, screen_resrcs: RandrScreenResources, output: X_RROutput):
  137. self._xdisplay = screen_resrcs._xdisplay
  138. self._output = output
  139. self._p = Xrandr.XRRGetOutputInfo(
  140. self._xdisplay,
  141. screen_resrcs._p,
  142. output,
  143. )
  144. def __del__(self):
  145. X11.XFree(self._p)
  146. @property
  147. def enabled(self):
  148. return self._p.contents.crtc != 0
  149. @property
  150. def connected(self):
  151. return self._p.contents.connection == X_RR_Connected
  152. @property
  153. def name(self):
  154. return self._p.contents.name.decode()
  155. def _get_property_atoms_list(self):
  156. nprop = ctypes.c_int()
  157. props = Xrandr.XRRListOutputProperties(
  158. self._xdisplay,
  159. self._output,
  160. ctypes.pointer(nprop),
  161. )
  162. atoms = [props[i] for i in range(nprop.value)]
  163. X11.XFree(props)
  164. return atoms
  165. def has_backlight(self):
  166. atom = X11.XInternAtom(self._xdisplay, b'Backlight', True)
  167. if atom:
  168. props = self._get_property_atoms_list()
  169. return atom in props
  170. else:
  171. return False
  172. def process(connected, disabled, enabled, backlight, no_backlight):
  173. xdisplay = X11.XOpenDisplay(None)
  174. screen_resrcs = RandrScreenResources(
  175. xdisplay,
  176. X11.XDefaultRootWindow(xdisplay),
  177. )
  178. found = False
  179. for output_info in screen_resrcs.get_output_infos():
  180. if ((not connected or output_info.connected)
  181. and (not disabled or not output_info.enabled)
  182. and (not enabled or output_info.enabled)
  183. and (not backlight or output_info.has_backlight())
  184. and (not no_backlight or not output_info.has_backlight())):
  185. found = True
  186. print(output_info.name)
  187. X11.XCloseDisplay(xdisplay)
  188. return found
  189. def _init_argparser():
  190. import argparse
  191. argparser = argparse.ArgumentParser(
  192. description='Show names of outputs available to the X server.'
  193. + ' The exit status is 0 if an output matching the specified criteria'
  194. + ' was found, otherwise 1.',
  195. )
  196. argparser.add_argument(
  197. '-c', '--connected',
  198. action='store_true',
  199. help='connected only',
  200. )
  201. argparser.add_argument(
  202. '-d', '--disabled',
  203. action='store_true',
  204. help='disabled only (does not imply --connected)',
  205. )
  206. argparser.add_argument(
  207. '-e', '--enabled',
  208. action='store_true',
  209. help='enabled only (does not imply --connected)',
  210. )
  211. argparser.add_argument(
  212. '-b', '--backlight',
  213. action='store_true',
  214. help='outputs with backlight configurable via randr only',
  215. )
  216. argparser.add_argument(
  217. '-B', '--no-backlight',
  218. action='store_true',
  219. help='outputs without backlight configurable via randr only',
  220. )
  221. return argparser
  222. def main(argv):
  223. argparser = _init_argparser()
  224. try:
  225. import argcomplete
  226. except ImportError:
  227. pass
  228. args = argparser.parse_args(argv)
  229. return 0 if process(**vars(args)) else 1
  230. if __name__ == "__main__":
  231. import sys
  232. sys.exit(main(sys.argv[1:]))