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 &attr32); 46 </code></pre> 47 48 <pre><code>// xcbの場合 49 uint32_t attr32[2] = { 0, colormap32 }; // 値はなんでもよさそう。 50 xcb_create_window(conn, 32, window32, screen->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 &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 & (CWBorderPixmap | CWBorderPixel)) == 0) && 71 (class != InputOnly) && (depth != pParent->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, &vi32) < 0) { 89 fatal("32bit-deep visual info not found"); 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, &template, &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, &visual32) < 0) { 120 fatal("32bit visual not found"); 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 > 0; xcb_depth_next(&depth_iter)) { 128 xcb_depth_t *d = depth_iter.data; 129 if (d->depth != 32) { 130 continue; 131 } 132 xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(d); 133 while (visual_iter.rem > 0) { 134 xcb_visualtype_t *v = visual_iter.data; 135 if (v->red_mask == 0xff0000 && v->green_mask == 0x00ff00 && v->blue_mask == 0x0000ff) { 136 *return_visualtype = *v; 137 return 0; 138 } 139 xcb_visualtype_next(&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->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>