X11 extensionsのXRandRでディスプレイの名前と使用できる解像度とリフレッシュレートを取得してみる
man見たりしたけど、XRRScreenResourcesとかが見当たらなかったのでX11/extension/Xrandr.hの転載をのせつつメモ。
XRandRのバージョンが1.2以上なら使えるはずです。
準備
以下のヘッダをインクルードします。
#include <X11/extension/Xrandr.h>
まずXRRGetScreenResourcesを使って、XRRScreenResourcesのポインタを取得します。XRRScreenResoucesのoutputsはディスプレイの数だけ要素があるRROutputの配列で、要素数はnoutputに格納されています。RROutputはXIDのtypedefです。使い終わったらXRRFreeScreenResourcesで解放しましょう。
typedef struct _XRRScreenResources { Time timestamp; Time configTimestamp; int ncrtc; RRCrtc *crtcs; int noutput; RROutput *outputs; int nmode; XRRModeInfo *modes; } XRRScreenResources; XRRScreenResources * XRRGetScreenResources (Display *dpy, Window window); void XRRFreeScreenResources (XRRScreenResources *resources);
名前の取得
ディスプレイの名前を取得するにはXRRGetOutputInfoを使ってXRROutputInfoのポインタを取得します。XRROutputInfoのnameに名前の文字列、nameLenにその文字列の長さが格納されています。使い終わったらXRRFreeOutputInfoで解放しましょう。
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; XRROutputInfo * XRRGetOutputInfo (Display *dpy, XRRScreenResources *resources, RROutput output); void XRRFreeOutputInfo (XRROutputInfo *outputInfo);
解像度とリフレッシュレートの取得
XRRScreenResourcesのメンバにmodesというのがあって、XRRModeInfoの配列になっています。その要素数はXRRScreenResourcesのnmodeです。解像度はXRRModeInfoのwidthとheightに格納されています。
typedef unsigned long XRRModeFlags; typedef struct _XRRModeInfo { RRMode id; unsigned int width; unsigned int height; unsigned long dotClock; unsigned int hSyncStart; unsigned int hSyncEnd; unsigned int hTotal; unsigned int hSkew; unsigned int vSyncStart; unsigned int vSyncEnd; unsigned int vTotal; char *name; unsigned int nameLength; XRRModeFlags modeFlags; } XRRModeInfo;
リフレッシュレートはXRRModeInfoを使って求める必要があり、xrandr-1.4のソースの540行目以降からパクったを参考にした実装例は以下のようになります。一応C++です。
double mode_refresh(XRRModeInfo const& info) { auto v_total = info.vTotal; if( info.modeFlags & RR_DoubleScan ) { v_total *= 2; } if( info.modeFlags & RR_Interlace ) { v_total /= 2; } return info.hTotal && v_total ? static_cast< double >( info.dotClock ) / ( static_cast< double >( info.hTotal ) * v_total ) : 0; }
例
実装例で一応C++です。本当はXRRQueryVersionなどを使ってXRandRを使っているかどうかやバージョンを調べる必要とかありますが面倒なので省略。mode_refreshは上の方を見てください。
int main() { Display* disp = XOpenDisplay( nullptr ); auto res = XRRGetScreenResources( disp, XRootWindow( disp, DefaultScreen( disp ) ) ); for( int i = 0; i < res->noutput; ++i ) { // 名前の表示 auto info = XRRGetOutputInfo( disp, res, res->outputs[i] ); std::cout << std::string( info->name, info->nameLen ) << " : " << std::endl; // 使える解像度とリフレッシュレートを列挙 for( int j = 0; j < res->nmode; ++j ) { std::cout << " " << res->modes[j].width << "x" << res->modes[j].height << "-" << mode_refresh( res->modes[j] ) << std::endl; } XRRFreeOutputInfo( info ); } XRRFreeScreenResources( res ); XCloseDisplay( disp ); }