SHAPE 拡張機能
SHAPE 拡張機能を使うことで、ウィンドウを四角形以外の形状にすることができます。
(範囲外を透明にする形になります)
形状については、単純に、複数の矩形座標のリストから生成されるので、縁を半透明にするようなことはできません。
ウィンドウの本来の四角形の範囲内において、指定された領域に含まれていない範囲は、画面上では透明になります。
その範囲では、後ろのウィンドウの内容が表示され、その範囲内で起きたポインタイベントなども、後ろのウィンドウを対象として動作します。
(範囲外を透明にする形になります)
形状については、単純に、複数の矩形座標のリストから生成されるので、縁を半透明にするようなことはできません。
ウィンドウの本来の四角形の範囲内において、指定された領域に含まれていない範囲は、画面上では透明になります。
その範囲では、後ろのウィンドウの内容が表示され、その範囲内で起きたポインタイベントなども、後ろのウィンドウを対象として動作します。
必要なもの
<X11/extensions/shape.h> のインクルードと、-lXext のリンクが必要です。
※ Xext ライブラリは、複数の一般的な拡張機能を含めたライブラリです。
※ Xext ライブラリは、複数の一般的な拡張機能を含めたライブラリです。
領域
SHAPE 拡張機能においては、各ウィンドウに対して、以下の3つの領域が定義されます。
※「ウィンドウの境界線」とは、ウィンドウ属性の border_pixel などで設定できる、ウィンドウ中身の周りに描画される境界線のことです。ウィンドウ装飾とは関係ありません。
境界領域 (Bounding) | 親ウィンドウ内で、このウィンドウが占めている領域 (境界線を含む)。 この範囲外では、ウィンドウ内容が透明になる。 |
---|---|
クリップ領域 (Clip) | 子ウィンドウが表示される領域、また、グラフィックスで描画できる領域。 境界領域内で、かつクリップ領域外にあたる範囲は、そのウィンドウの境界線の領域として扱われる。 |
入力領域 (Input) | ポインタがこの領域にある場合、このウィンドウ上にポインタが存在するものとする。 |
※「ウィンドウの境界線」とは、ウィンドウ属性の border_pixel などで設定できる、ウィンドウ中身の周りに描画される境界線のことです。ウィンドウ装飾とは関係ありません。
形状指定がない場合
形状の指定がない場合、デフォルトの領域は、以下のようになります。
境界領域と入力領域は、「ウィンドウの境界線を含む矩形」。
クリップ領域は、「ウィンドウの境界線を含まない中身の矩形」。
境界線の幅が 0 の場合は、すべて同じになります。
境界領域と入力領域は、「ウィンドウの境界線を含む矩形」。
クリップ領域は、「ウィンドウの境界線を含まない中身の矩形」。
境界線の幅が 0 の場合は、すべて同じになります。
領域について
各領域は、ウィンドウの本来の矩形よりも大きな範囲を指定できますが、実際に表示されるのは、本来の領域内までです。
クリップ領域と入力領域については、境界領域の範囲内のみ有効になります。
基本的には、境界領域だけを変更して、形状を指定すれば、領域外の部分は透明扱いになります。
クリップ領域と入力領域については、境界領域の範囲内のみ有効になります。
基本的には、境界領域だけを変更して、形状を指定すれば、領域外の部分は透明扱いになります。
領域の指定方法
ウィンドウ形状を指定したい場合、以下のような複数の方法があります。
ウィンドウに形状が設定されていない場合、ウィンドウの現在の領域は、通常のデフォルトの領域となります。
ウィンドウの現在の各領域を、指定された結合方法で結合できます。
詳しくは、SHAPE 拡張機能 の関数リストをご覧ください。
- Xlib の XPolygonRegion() で多角形の Region を作成して、XShapeCombineRegion() によって領域を変更する。
- XShapeCombineRectangles() で、複数の矩形のリストから領域を変更する。
- 1bit の Pixmap を使って、XShapeCombineMask() で領域をマスクする。
ウィンドウに形状が設定されていない場合、ウィンドウの現在の領域は、通常のデフォルトの領域となります。
ウィンドウの現在の各領域を、指定された結合方法で結合できます。
詳しくは、SHAPE 拡張機能 の関数リストをご覧ください。
プログラム
ひし形のウィンドウ形状にします。
閉じるボタンか、ひし形内でポインタボタンを押すと終了します。
※通常のウィンドウなので、ウィンドウマネージャによる装飾フレームも付いています。
<e02-shape.c>
形状を指定する場合、通常は、ウィンドウマネージャによる装飾フレームは必要ないと思うので、ウィンドウ属性を override_redirect = True にしてウィンドウを作成することになると思いますが、装飾フレームを付けたまま形状を指定することもできるので、ウィンドウにぽっかり穴を開けて、透けている範囲のスクリーンショットを撮るようなアプリケーションを作ることもできます。
閉じるボタンか、ひし形内でポインタボタンを押すと終了します。
※通常のウィンドウなので、ウィンドウマネージャによる装飾フレームも付いています。
$ cc -o run e02-shape.c util.c -lX11 -lXext
<e02-shape.c>
#include <stdio.h> #include <X11/Xlib.h> #include <X11/extensions/shape.h> #include "util.h" #define WIDTH 101 #define HEIGHT 101 static void _set_shape(Display *disp,Window win) { Region r; XPoint pt[5]; pt[0].x = WIDTH / 2, pt[0].y = 0; pt[1].x = WIDTH - 1, pt[1].y = HEIGHT / 2; pt[2].x = WIDTH / 2, pt[2].y = HEIGHT - 1; pt[3].x = 0, pt[3].y = HEIGHT / 2; pt[4] = pt[0]; r = XPolygonRegion(pt, 5, EvenOddRule); XShapeCombineRegion(disp, win, ShapeBounding, 0, 0, r, ShapeSet); XDestroyRegion(r); } int main(int argc,char **argv) { Display *disp; Window win; XEvent ev; int major,minor; disp = XOpenDisplay(NULL); if(!disp) return 1; set_display(disp); if(!XShapeQueryVersion(disp, &major, &minor)) printf("unsupported SHAPE\n"); else printf("SHAPE ver %d.%d\n", major, minor); // win = create_test_window2(disp, WIDTH, HEIGHT, 0, ButtonPress); _set_shape(disp, win); //イベント XMapWindow(disp, win); while(1) { XNextEvent(disp, &ev); if(event_quit(&ev)) break; if(ev.type == ButtonPress) break; } XCloseDisplay(disp); return 0; }
形状を指定する場合、通常は、ウィンドウマネージャによる装飾フレームは必要ないと思うので、ウィンドウ属性を override_redirect = True にしてウィンドウを作成することになると思いますが、装飾フレームを付けたまま形状を指定することもできるので、ウィンドウにぽっかり穴を開けて、透けている範囲のスクリーンショットを撮るようなアプリケーションを作ることもできます。