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


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