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 (6084B)


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