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 &attr32); 25 </code></pre> 26 27 <pre><code>// xcbの場合 28 uint32_t attr32[2] = { 0, colormap32 }; // 値はなんでもよさそう。 29 xcb_create_window(conn, 32, window32, screen->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 &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 & (CWBorderPixmap | CWBorderPixel)) == 0) && 50 (class != InputOnly) && (depth != pParent->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, &vi32) < 0) { 68 fatal("32bit-deep visual info not found"); 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, &template, &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, &visual32) < 0) { 99 fatal("32bit visual not found"); 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 > 0; xcb_depth_next(&depth_iter)) { 107 xcb_depth_t *d = depth_iter.data; 108 if (d->depth != 32) { 109 continue; 110 } 111 xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(d); 112 while (visual_iter.rem > 0) { 113 xcb_visualtype_t *v = visual_iter.data; 114 if (v->red_mask == 0xff0000 && v->green_mask == 0x00ff00 && v->blue_mask == 0x0000ff) { 115 *return_visualtype = *v; 116 return 0; 117 } 118 xcb_visualtype_next(&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->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