#!/usr/bin/env python3 # PYTHON_ARGCOMPLETE_OK """ https://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c """ import ctypes import ctypes.util X_Time = ctypes.c_ulong """ #ifndef _XTYPEDEF_XID # define _XTYPEDEF_XID # ifndef _XSERVER64 typedef unsigned long XID; # else typedef CARD32 XID; # endif #endif """ X_XID = ctypes.c_ulong """ typedef XID RROutput; """ X_RROutput = X_XID """ typedef XID RRCrtc; """ X_RRCrtc = X_XID """ /usr/include/X11/extensions/Xrandr.h typedef XID RRMode; """ X_RRMode = X_XID """ /usr/include/X11/extensions/randr.h #define RR_Connected 0 """ X_RR_Connected = 0 """ /usr/include/X11/extensions/randr.h typedef unsigned short Connection; """ X_Connection = ctypes.c_ushort """ /usr/include/X11/extensions/randr.h typedef unsigned short SubpixelOrder; """ X_SubpixelOrder = ctypes.c_ushort class X_XRRScreenResources(ctypes.Structure): """ /usr/include/X11/extensions/Xrandr.h typedef struct _XRRScreenResources { Time timestamp; Time configTimestamp; int ncrtc; RRCrtc *crtcs; int noutput; RROutput *outputs; int nmode; XRRModeInfo *modes; } XRRScreenResources; """ _fields_ = [ ('timestamp', X_Time), ('configTimestamp', X_Time), ('ncrtc', ctypes.c_int), ('crtcs', ctypes.POINTER(X_RRCrtc)), ('noutput', ctypes.c_int), ('outputs', ctypes.POINTER(X_RROutput)), ('nmode', ctypes.c_int), ('modes', ctypes.c_void_p), # ctypes.POINTER(XRRModeInfo) ] class X_XRROutputInfo(ctypes.Structure): """ typedef struct _XRROutputInfo { Time timestamp; RRCrtc crtc; char *name; int nameLen; unsigned long mm_width; unsigned long mm_height; Connection connection; SubpixelOrder subpixel_order; int ncrtc; RRCrtc *crtcs; int nclone; RROutput *clones; int nmode; int npreferred; RRMode *modes; } XRROutputInfo; """ _fields_ = [ ('timestamp', X_Time), ('crtc', X_RRCrtc), ('name', ctypes.c_char_p), ('nameLen', ctypes.c_int), ('mm_width', ctypes.c_ulong), ('mm_height', ctypes.c_ulong), ('connection', X_Connection), ('subpixel_order', X_SubpixelOrder), ('ncrtc', ctypes.c_int), ('crtcs', ctypes.POINTER(X_RRCrtc)), ('nclone', ctypes.c_int), ('clones', ctypes.POINTER(X_RROutput)), ('nmode', ctypes.c_int), ('npreferred', ctypes.c_int), ('modes', ctypes.POINTER(X_RRMode)), ] X11 = ctypes.cdll.LoadLibrary("libX11.so") Xrandr = ctypes.cdll.LoadLibrary("libXrandr.so") Xrandr.XRRGetScreenResourcesCurrent.restype = \ ctypes.POINTER(X_XRRScreenResources) libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c')) """ XRROutputInfo * XRRGetOutputInfo (Display *dpy, XRRScreenResources *resources, RROutput output); """ Xrandr.XRRGetOutputInfo.restype = ctypes.POINTER(X_XRROutputInfo) class RandrOutputInfo: def __init__(self, xdisplay, screen_resrcs: ctypes.POINTER(X_XRRScreenResources), output: X_RROutput): self._p = Xrandr.XRRGetOutputInfo(xdisplay, screen_resrcs, output) def __del__(self): libc.free(self._p) @property def enabled(self): return self._p.contents.crtc != 0 @property def connected(self): return self._p.contents.connection == X_RR_Connected @property def name(self): return self._p.contents.name.decode() def get_xrandr_output_infos(xdisplay): screen_resrcs = Xrandr.XRRGetScreenResourcesCurrent( xdisplay, X11.XDefaultRootWindow(xdisplay), ) assert isinstance(screen_resrcs.contents, X_XRRScreenResources) return [RandrOutputInfo(xdisplay, screen_resrcs, screen_resrcs.contents.outputs[o]) for o in range(screen_resrcs.contents.noutput)] def process(connected, disabled, enabled): xdisplay = X11.XOpenDisplay(None) for output_info in get_xrandr_output_infos(xdisplay): if ((not connected or output_info.connected) and (not disabled or not output_info.enabled) and (not enabled or output_info.enabled)): print(output_info.name) X11.XCloseDisplay(xdisplay) def _init_argparser(): import argparse argparser = argparse.ArgumentParser( description='Show names of outputs available to the X server.', ) argparser.add_argument( '-c', '--connected', action='store_true', help='connected only', ) argparser.add_argument( '-d', '--disabled', action='store_true', help='disabled only (does not imply --connected)', ) argparser.add_argument( '-e', '--enabled', action='store_true', help='enabled only (does not imply --connected)', ) return argparser def main(argv): argparser = _init_argparser() try: import argcomplete except ImportError: pass args = argparser.parse_args(argv) process(**vars(args)) return 0 if __name__ == "__main__": import sys sys.exit(main(sys.argv[1:]))