X11: 拡張機能の基本

拡張機能の基本
X のコアプロトコルで実現できない機能は、それぞれ拡張機能として追加されています。

ただし、拡張機能を実際に実装しているのは X サーバーなので、クライアントが接続する X サーバーによって、拡張機能のサポート状況が異なります。

クライアントが拡張機能を使いたい場合は、現在接続している X サーバーで、その拡張機能が使用できるかどうかを、まず確認する必要があります。
※他の拡張機能を使用する、拡張機能もあります。

また、クライアントが拡張機能の関数を使う際は、主に X11/extensions/ に存在するインクルードファイルをインクルードし、拡張機能それぞれで (クライアント用の) ライブラリをリンクする必要があります。
仕様
各拡張機能の仕様は、X.Org によって管理されています。
https://www.x.org/releases/current/doc/index.html

上記のドキュメントでは、「プロトコル」と「ライブラリ」の2つの仕様が存在する場合があります。

「プロトコル」用のドキュメントは、基本的に、X サーバーが機能を実装する時や、クライアント向けのライブラリを作るための仕様です。
「ライブラリ」用のドキュメントは、クライアントが使用する関数などの説明です。

プロトコル用のドキュメントしか存在しなかったり、ライブラリ用のドキュメントが最新バージョンに対応していない場合があるため、注意してください。
ぞれぞれの関数や定数は、拡張機能ごとのインクルードファイルで確認してください。
Xlib 関数
Xlib には、以下の拡張機能関連の関数があります。
ただし、基本的には、各拡張機能ごとに、それぞれのバージョンや情報を取得するための、同じような関数が定義されているので、そのような関数が存在する場合は、そちらを使います。
拡張機能名の一覧を取得
char **XListExtensions(Display *display, int *nextensions_return);

int XFreeExtensionList(char **list);

XListExtensions 関数を使うと、X サーバーでサポートされている、名前付きの拡張機能の名前をすべて取得できます。
nextensions_return に、その数が返ります。

戻り値で、(char *) の配列が返ります。
使用後は、XFreeExtensionList 関数で解放します。
拡張機能の情報を取得
Bool XQueryExtension(Display *display, char *name,
    int *major_opcode_return, int *first_event_return, int *first_error_return);

拡張機能が名前付きで X サーバーに登録されている場合、各機能の名前から、情報を取得します。

name拡張機能の名前
major_opcode_returnこの拡張機能用のオペコードが返る。0 でなし。
GenericEvent イベントの判定などで使う場合があります。
first_event_returnこの拡張機能に追加のイベントタイプがある場合、ベース値 (先頭の数値) が返る。0 でなし
first_error_returnこの拡張機能に追加のエラーコードがある場合、ベース値が返る。0 でなし
戻り値True で、指定名の拡張機能が存在する
拡張機能のイベント
それぞれの拡張機能で X イベントが存在する場合、XQueryExtension 関数、または、拡張機能ごとのそれに相当する関数を使って取得した値で、拡張機能によって送られたイベントかどうかを判定することができます。

XInput2 などのように、GenericEvent を使う場合は、opcode を使います。
それ以外は、追加のイベントタイプのベース値を使います (上記の関数の場合、first_event_return)。
追加のイベントタイプのベース値
一般的な拡張機能では、通常の X イベントと同じような形でイベントが送られてくるので、XEvent の type 値からイベントタイプを判断します。

ただし、それぞれの拡張機能は、X サーバーごとに可変的にサポートされているので、イベントタイプの値を共通の固定値にすることはできません。

そのため、X サーバーに拡張機能が登録された時点で、拡張機能で必要になる数のイベントタイプ値が割り当てられるので、クライアントはその先頭値を取得することで、拡張機能のイベントタイプかどうかを判断することができます。
プログラム
X サーバーがサポートしている、各拡張機能の情報を取得して、表示します。

<e01-list.c>
#include <stdio.h>
#include <X11/Xlib.h>

int main(int argc,char **argv)
{
    Display *disp;
    char **names;
    int i,cnt,opcode,event,err;
    
    disp = XOpenDisplay(NULL);
    if(!disp) return 1;

    names = XListExtensions(disp, &cnt);

    for(i = 0; i < cnt; i++)
    {
        XQueryExtension(disp, names[i], &opcode, &event, &err);

        printf("[%s] opcode(%d) event(%d) error(%d)\n",
            names[i], opcode, event, err);
    }

    XFreeExtensionList(names);

    XCloseDisplay(disp);

    return 0;
}
結果
[Generic Event Extension] opcode(128) event(0) error(0)
[SHAPE] opcode(129) event(64) error(0)
[MIT-SHM] opcode(130) event(65) error(128)
[XInputExtension] opcode(131) event(66) error(129)
[XTEST] opcode(132) event(0) error(0)
[BIG-REQUESTS] opcode(133) event(0) error(0)
[SYNC] opcode(134) event(83) error(134)
[XKEYBOARD] opcode(135) event(85) error(137)
[XC-MISC] opcode(136) event(0) error(0)
[SECURITY] opcode(137) event(86) error(138)
[XFIXES] opcode(138) event(87) error(140)
[RENDER] opcode(139) event(0) error(142)
[RANDR] opcode(140) event(89) error(147)
[XINERAMA] opcode(141) event(0) error(0)
[Composite] opcode(142) event(0) error(0)
[DAMAGE] opcode(143) event(91) error(152)
[MIT-SCREEN-SAVER] opcode(144) event(92) error(0)
[DOUBLE-BUFFER] opcode(145) event(0) error(153)
[RECORD] opcode(146) event(0) error(154)
[DPMS] opcode(147) event(0) error(0)
[Present] opcode(148) event(0) error(0)
[DRI3] opcode(149) event(0) error(0)
[X-Resource] opcode(150) event(0) error(0)
[XVideo] opcode(151) event(93) error(155)
[GLX] opcode(152) event(95) error(158)
[XFree86-VidModeExtension] opcode(153) event(0) error(172)
[XFree86-DGA] opcode(154) event(112) error(179)
[DRI2] opcode(155) event(119) error(0)

opcode は順番に +1 されますが、イベントタイプやエラーコードの値は、拡張機能で必要になる分だけ加算されます。