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 &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->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">\ 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 & (CWBorderPixmap | CWBorderPixel)) == 0) && 56 (class != InputOnly) && (depth != pParent->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, &vi32) < 0) { 76 fatal("32bit-deep visual info not found"); 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, &template, &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, &visual32) < 0) { 108 fatal("32bit visual not found"); 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 > 0; xcb_depth_next(&depth_iter)) { 116 xcb_depth_t *d = depth_iter.data; 117 if (d->depth != 32) { 118 continue; 119 } 120 xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(d); 121 while (visual_iter.rem > 0) { 122 xcb_visualtype_t *v = visual_iter.data; 123 if (v->red_mask == 0xff0000 && v->green_mask == 0x00ff00 && v->blue_mask == 0x0000ff) { 124 *return_visualtype = *v; 125 return 0; 126 } 127 xcb_visualtype_next(&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->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>