X11で画面の解像度を変える
昔はXF86 Video Mode Extensionを使っていたのだが、これは最近のX.orgではうまく機能しなくなってしまったようだ。(互換のためにAPIは実装されているようだが、実質的に機能しない。)
現代的には、XRandR Extensionというものを使う。しかし、XRandRは、資料があまりない。その上、どういうわけか、関数とかデータ型とかの名前がめちゃめちゃだし、関数の仕様にも首をひねる部分が多く、理解を妨げる。
例えば、XRandRの基本のデータ構造は、XRRGetScreenInfo() という関数を呼ぶと得られるのだが、ここで得られるデータ構造の型名はXRRScreenConfigurationであって、XRRScreenInfoという名前のデータ構造は存在しない。XRRGetScreenInfo() は、動的に割り当てたXRRScreenConfigurationへのポインタを返すのだが、使い終わったらこのメモリをアプリ側で開放する必要がある。で、XRRScreenConfigurationを開放するための関数はXRRFreeScreenConfigInfo()というのだ。XRRFreeScreenInfoでも、XRRFreeScreenConfigurationでもなく。
誰だ、こういう名前つけたの。責任者出て来い、みたいな。
ということで、使い方のまとめ。(SL Viewerで使うものだけ。)
- #include <X11/extensions/Xrandr.h>
- XRandRを使うときには、X11の標準のヘッダに加えて、これをインクルードする。大文字小文字は、ここに書いてある通りにする必要がある (ファイルシステムにもよるが)。
- Status XRRQueryVersion(Display *dpy, int *major, int *minor)
- とにかく最初に呼ぶ。XRandR Extension がサポートされていれば戻り値は非0になる。サポートされていなければ0。majorとminorには、アプリ側で確保したint型の変数 (初期化不要) のアドレスをわたす。ここに、XRandRのバージョンのメジャーとマイナーが入って戻ってくる。普通は、majorが指す変数の値が1ならOK。minorは、使う関数によっては値をチェックする必要がある (1以上とか2以上とか) ようだが、以下の関数はバージョン1.0で使えるのでチェック不要。
- XRRScreenConfiguration *XRRGetScreenInfo(Display *dpy, Drawable draw)
- この関数を呼ぶと、XRRScreenCOnfiguration型のデータへのポインタが得られる。drawには、ディスプレイdpy配下にあるスクリーンのうち、解像度を変更しようとしているスクリーンのルートウィンドウを指定する。(スクリーン番号などではなく。なぜ、こんな仕様なのか不明。) 以下の関数の引数にconfigというパラメタがあったら、そこには、この関数の結果として得られたポインタをわたす。使い終わったら、XRRFreeScreenConfigInfoで開放する。
- void XRRFreeScreenConfigInfo(XRRScreenConfiguration *config)
- XRRGetScreenInfoで得たXRRScreenConfigurationを開放する。
- Time XRRConfigTimes(XRRScreenConfiguration *config, Time *timestamp)
- この関数は、XRRGetScreenInfoを使ってXRRScreenConfigurationを得た時刻を調べるのに使う。Time型が、引数 (ポインタ) と戻り値の両方に登場するが、両者に同じ値が返るらしい。時刻なんかどうでもいいと思うかもしれないが、この時刻は、あとでXRRSetScreenConfig()を呼ぶときに必要になる。
- XRRScreenSize *XRRConfigSizes(XRRScreenConfiguration *config, int *nsizes)
- 利用可能な解像度の一覧を得る。関数の結果はXRRScreenSizeへのポインタという型だが、実際には、XRRScreenSizeを要素型とする配列の先頭のポインタが得られる。アプリ側でint型の変数を用意 (初期化不要) して、そのアドレスをnsizesとしてわたすと、結果として得られる配列の大きさ (要素数) がセットされる。XRRScreenSizeというのはstructで、ここにwidthとheightというメンバがあって、それぞれ横方向、縦方向の解像度 (ドット数) を表している。
- Rotation XRRConfigRotations(XRRScreenConfiguration *config, Rotation *rotation)
- この関数は、現在の画面の回転状態 (90度回転させて縦長表示にできるようなもの) を得る。関数名はconfig rotations だが、configure するわけではないし、得られるのは回転状態を表す1個の値だ。引数でRotation型の変数のアドレスをわたすと、その変数に値がセットされると同時に、同じ値が戻り値としても返る。なお、サポートされている回転状態の一覧を調べる機能はないようだ。Xrandr.hに理論的に可能なすべての状態がマクロとして定義されているが、当然使えるものはハードによって異なるはず。どれが実際に使えるかを知るためには、実行時に試してみるしかないようだ。
- Status XRRSetScreenConfig(Display *dpy, XRRScreenConfiguration *config, Drawable draw, int size_index, Rotation rotation, Time timestamp)
- この関数で実際に解像度を変更する。XRRGetScreenInfo()と同じく、drawにはルートウィンドウを指定する。size_indexには、変更後の解像度を、XRRConfigSizes()の戻り値として得られた配列の添え字番号で指定する。rotationには、XRRConfigRotations()で得られた値をそのまま指定する (勝手な値を指定するとエラーになる模様)。timestampにはやはりXRRConfigTimes()で得られた値をそのまま指定する。この関数の戻り値はStatus型なのだが、値0が成功で、それ以外がエラー。
- なお、この関数は、XRRGetScreenInfo()を呼んでからすぐに呼ばないといけないらしく、時間が経つとエラーになってしまうそうだ。そのためにtimestampを渡すのだ、とも言われている。そして、時間が経った場合は、(いったんメモリを開放したあと) XRRGetScreenInfo() からやり直す、という記述も見かける。しかし、関数が非0を返したときに、そのエラーの原因が、時間が経ったためなのか、他の理由なのかを区別する方法が不明。いったい、なんなんだ、この仕様は。
« ネクソンジャパンの社長さん | トップページ | Linux »


XRandRの資料がないと愚痴を書いたところ、詳しい資料のありかを教えていただきました。(URLがめちゃめちゃ長くて表示は途中で切れてます。)
http://gitweb.freedesktop.org/?p=users/keithp/randrproto.git;a=blob;h=f0ec5e1326565e7008056159249df2329eab1156;hb=61d60a93dc0c827ef970f21f6b80099cc6c958f1;f=randrproto.txt">
http://gitweb.freedesktop.org/?p=users/keithp/randrproto.git;a=blob;h=f0ec5e1326565e7008056159249df2329eab1156;hb=61d60a93dc0c827ef970f21f6b80099cc6c958f1;f=randrproto.txt
だそうです。
あのー、これって、APIというか、その下で流れているプロトコルの資料じゃないですか。しかも、このURLはgitレポジトリ。でもって、users/keithpの下ですか? つまり、これは、XRandRの開発の中心人物であるKeith Packardさんの、個人的なメモなわけですね…。ま、いいけど。
今度、暇なときにゆっくり読みます。(って、今が暇なときなんですけどね。)
投稿: Alissa Sabre | 2008年1月 3日 (木) 13時34分
おしえていただいた資料を読んだところ、いろいろと間違いに気づき、いくつかの謎も解決し、そして、このエントリに書いたインターフェースはすでに時代後れ (obsolete) だから使わない方がいい、ということまでわかりました…。
しょうがないんで、今から書き直します。Linux用。
投稿: Alissa Sabre | 2008年1月 5日 (土) 18時05分