www.mtkn.jp

Manuscripts for my personal webpage.
git clone https://git.mtkn.jp/www.mtkn.jp
Log | Files | Refs | LICENSE

x11_32bit_window.html (6063B)


      1 <h1>X11で深さが32bitのwindowを作成する</h1>
      2 <time>2025-12-20</time>
      3 
      4 <h2>結論</h2>
      5 <p>
      6 X11のrender拡張機能で半透明な画像を合成(composite)する際に深さが32bitのウィンドウを作成する必要がある。\
      7 その際ドキュメントにも書いてなさそうな操作が必要だった。\
      8 ウィンドウを作成する際に<code>border pixel</code>の値を設定する必要がある(言語はC):
      9 </p>
     10 
     11 <pre><code>\
     12 // Xlibの場合
     13 XSetWindowAttributes attr32 = {
     14 	.border_pixel = 0, // 値はなんでもよさそう
     15 	.colormap = colormap32,
     16 }
     17 Window window32 = XCreateWindow(display, DefaultRootWindow(display),
     18 	0, 0, 1, 1, 0,
     19 	32, // depth
     20 	InputOutput,
     21 	visual32,
     22 	CWBorderPixel|CWColormap, // CWBorderPixelを指定
     23 	&amp;attr32);
     24 </code></pre>
     25 
     26 <pre><code>\
     27 // xcbの場合
     28 uint32_t attr32[2] = { 0, colormap32 }; // 値はなんでもよさそう。
     29 xcb_create_window(conn, 32, window32, screen-&gt;root,
     30 	0, 0, 1, 1, 0,
     31 	XCB_WINDOW_CLASS_INPUT_OUTPUT,
     32 	visual32,
     33 	XCB_CW_BORDER_PIXEL|XCB_CW_COLORMAP, // XCB_CW_BORDER_PIXELを指定
     34 	&amp;attr32);
     35 </code></pre>
     36 
     37 <h2>出典</h2>
     38 <p>
     39 Go言語の<a href="https://cs.opensource.google/go/x/exp/+/8475f288:shiny/driver/x11driver/screen.go;drc=7b9b53b0aca47495e3a71d360c959fe1f14b5756;l=622">golang.org/x/exp/shiny/driver/x11driver/screen.go:622</a>に、
     40 </p>
     41 <blockquote cite="https://cs.opensource.google/go/x/exp/+/8475f288:shiny/driver/x11driver/screen.go;drc=7b9b53b0aca47495e3a71d360c959fe1f14b5756;l=622">\
     42 <pre><code>	// The CwBorderPixel attribute seems necessary for depth == 32. See
     43 	// http://stackoverflow.com/questions/3645632/how-to-create-a-window-with-a-bit-depth-of-32
     44 </code></pre>
     45 </blockquote>
     46 <p>
     47 と書いていた。\
     48 引用元を見るとXサーバーのソースコードを参照しており、\
     49 そのコードでは親のウィンドウの深さと異なる深さのウィンドウを作成する場合、\
     50 <code>CWBorderPixmap</code>又は<code>CWBorderPixel</code>を指定しないと<code>BadMatch</code>\
     51 というエラーが返ってくるようになっている。\
     52 理由はよく分からない:
     53 </p>
     54 <blockquote cite="https://cgit.freedesktop.org/xorg/xserver/tree/dix/window.c?h=xorg-server-21.1.21#n818">
     55 <pre><code>	if (((vmask &amp; (CWBorderPixmap | CWBorderPixel)) == 0) &amp;&amp;
     56 		(class != InputOnly) &amp;&amp; (depth != pParent-&gt;drawable.depth)) {
     57 		*error = BadMatch;
     58 		return NullWindow;
     59 	}
     60 </code></pre>
     61 </blockquote>
     62 
     63 <h2>深さ32bitのウィンドウの作成手順</h2>
     64 <h3>深さ32bitのヴィジュアルを取得</h3>
     65 <p>ウィンドウ作成の関数(<code>XCreateWindow</code>または<code>xcb_create_window</code>)に渡す32bitのヴィジュアルを\
     66 取得する:
     67 </p>
     68 <pre><code>\
     69 // xlibの場合
     70 int findVisual32(Display *display, XVisualInfo *return_visual_info);
     71 /* ... */
     72 int main(void) {
     73 	/* ... */
     74 	XVisualInfo vi32;
     75 	if (findVisual32(display, &amp;vi32) &lt; 0) {
     76 		fatal(&quot;32bit-deep visual info not found&quot;);
     77 	}
     78 	/* ... */
     79 }
     80 /* ... */
     81 int findVisual32(Display *display, XVisualInfo *return_visual_info) {
     82 	long mask = VisualDepthMask|VisualRedMaskMask|VisualGreenMaskMask|VisualBlueMaskMask;
     83 	XVisualInfo template = {
     84 		.depth      = 32,
     85 		.red_mask   = 0xff0000,
     86 		.green_mask = 0x00ff00,
     87 		.blue_mask  = 0x0000ff,
     88 	};
     89 	int n;
     90 	XVisualInfo *vinfos = XGetVisualInfo(display, mask, &amp;template, &amp;n);
     91 	if (n == 0) {
     92 		return -1;
     93 	}
     94 	*return_visual_info = vinfos[0];
     95 	XFree(vinfos);
     96 	return 0;
     97 }
     98 </pre></code>
     99 
    100 <pre><code>\
    101 // xcbの場合
    102 int findVisual32(xcb_screen_t *screen, xcb_visualtype_t *return_visualtype);
    103 /* ... */
    104 int main(void) {
    105 	/* ... */
    106 	xcb_visualtype_t visual32;
    107 	if (findVisual32(screen, &amp;visual32) &lt; 0) {
    108 		fatal(&quot;32bit visual not found&quot;);
    109 	}
    110 	/* ... */
    111 }
    112 /* ... */
    113 int findVisual32(xcb_screen_t *screen, xcb_visualtype_t *return_visualtype) {
    114 	xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen);
    115 	for (;depth_iter.rem &gt; 0; xcb_depth_next(&amp;depth_iter)) {
    116 		xcb_depth_t *d = depth_iter.data;
    117 		if (d-&gt;depth != 32) {
    118 			continue;
    119 		}
    120 		xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(d);
    121 		while (visual_iter.rem &gt; 0) {
    122 			xcb_visualtype_t *v = visual_iter.data; 
    123 			if (v-&gt;red_mask == 0xff0000 &amp;&amp; v-&gt;green_mask == 0x00ff00 &amp;&amp; v-&gt;blue_mask == 0x0000ff) {
    124 				*return_visualtype = *v;
    125 				return 0;
    126 			}
    127 			xcb_visualtype_next(&amp;visual_iter);
    128 		}
    129 	}
    130 	return -1;
    131 }
    132 </code></pre>
    133 
    134 <h3>深さ32bitのカラーマップを作成</h3>
    135 <p>ウィンドウ作成の関数(<code>XCreateWindow</code>または<code>xcb_create_window</code>)に渡す32bitのカラーマップを\
    136 作成する。
    137 </p>
    138 <pre><code>\
    139 // xlibの場合
    140 	Colormap colormap32 = XCreateColormap(display, DefaultRootWindow(display), vi32.visual, AllocNone);
    141 </code></pre>
    142 <pre><code>\
    143 // xcbの場合
    144 	xcb_colormap_t colormap32 = xcb_generate_id(conn);
    145 	xcb_create_colormap(conn, XCB_COLORMAP_ALLOC_NONE, colormap32, screen-&gt;root, visual32.visual_id);
    146 </code></pre>
    147 
    148 <h3>深さ32bitのウィンドウを作成</h3>
    149 <p>最後にウィンドウを作成する:</p>
    150 <pre><code>\
    151 // xlibの場合
    152 	Window window32 = XCreateWindow(display, DefaultRootWindow(display),
    153 		0, 0, 1, 1, 0,
    154 		32,
    155 		InputOutput,
    156 		vi32.visual,
    157 		CWBorderPixel|CWColormap,
    158 		&attr32);
    159 </code></pre>
    160 <pre><code>\
    161 // xcbの場合
    162 	uint32_t attr32[2] = { 0, colormap32 }; 
    163 	xcb_create_window(conn, 32, window32, screen->root,
    164 		0, 0, 1, 1, 0,
    165 		XCB_WINDOW_CLASS_INPUT_OUTPUT,
    166 		visual32.visual_id,
    167 		XCB_CW_BORDER_PIXEL|XCB_CW_COLORMAP, &attr32);
    168 </code></pre>
    169 
    170 <h2>サンプルコード</h2>
    171 32bitのウィンドウを作成し、そこからrender拡張機能を使って半透明な四角形を描画するプログラムを作った。\
    172 OpenBSDで動作確認した。他のUnixでも多分動くと思う:<br>
    173 <a href="https://git.mtkn.jp/win32">git.mtkn.jp/win32</a>
    174 
    175 <h2>参考文献</h2>
    176 <ol>
    177 <li><a href="https://azelpg.gitlab.io/azsky2/note/prog/x11/03_visual.html">X11: ビジュアル</a></li>
    178 </ol>