LECTURE 18 矩形でないウィンドウの表示

○ はじめに

突然ですが、これまでに表示してきたウィンドウは全て四角系でした。まあ困ることはそんなに無いかもしれませんが、例えば丸いボタンをウィンドウとして作れないのか?とか、あの丸い時計のアプリケーションはどうやってあの形のウィンドウを表示しているのか? などといったふとした疑問が湧いて来ることはありませんか?

X には拡張機能と呼ばれる機能があって、その中の一つである SHAPE Extension という機能を使うことで四角形以外のウィンドウを表示することが出来ます。

ここでは、SHAPE Extension を使用する際の前提事項をまず説明した後に SHAPE Extension の使い方を説明します。

○ bounding region と clip region

SHAPE extension から導入された考え方ですが、全ての Window は bounding region と clip region と呼ばれる領域から構成されます。

bounding region とは、ボーダを含んだ Window の形を表す領域を表します。clip region は bounding region の一部であり、グラフィックスを描画したり子ウィンドウを表示したりできる領域を表します。よって bounding region と clip region の間に挟まれる領域がボーダとなります。

018region.jpg

通常の Window では bounding region および clip region 共に矩形であると考えれば、全ての形の Window について同様に考えることができます。なお、矩形の Window の bounding region および clip region をそれぞれデフォルトの bounding region、clip region と呼びます。

bounding region および clip region は自由に変更することができます。仮に、作成した Window よりも大きい領域を bounding region および clip region として設定した場合、Window からはみ出る部分は無視されます。しかし Window の表示領域は動的に計算されるため、Window の大きさをマウスのドラッグなどで大きくした場合には、より大きな region が表示される様になります。

○ サンプルプログラム

非矩形のウィンドウをボタンとして表示し、クリックする度にボタンの表示色を変化させるサンプルプログラム xshape.c です。また、使用している X11 ビットマップ btn_bd.h および btn_cl.h も併せてリンクしておきます。ブラウザ上はヘッダの内容ではなくビットマップイメージが表示されるかもしれません。その場合はソースを見るなどして下さい。はじめに のページから、全てのサンプルプログラムを固めた tar ボールをダウンロードすることもできます。

これまでのサンプルでは X のライブラリのリンク指定は -lX11 のみで良かったのですが、ここでは拡張機能を使用しているので、-lXext も同時に指定して下さい。

gcc -I/usr/X11R6/include -L/usr/X11R6/lib -o xshape xshape.c -lX11 -lXext

X11 ビットマップデータは bitmap コマンドで作ることができます。が、僕は面倒だったので、まず Xlib で円と長方形を使ってボタンの形を表示したウィンドウを作ってそれを画像ツールでダンプし、白黒 2 色の X11 ビットマップとして保存しました。

実行直後は、背景色が青のウィンドウ上に白色で非矩形のウィンドウ ( ボタン ) が表示されます。ボタンをマウスの左ボタンでクリックする度に、白=>赤、赤=>白と表示色が変化します。ウィンドウに関わらず、マウスの右ボタンをクリックすると終了します。

018white.jpg

↑と↓が交互に切り替わります。

018red.jpg

--- xshape.c ---

    1	/*
    2	 * Shape Extension を使って矩形ではない Window を表示するサンプルコード
    3	 */
    4	
    5	#include <stdio.h>
    6	#include <X11/Xlib.h>
    7	#include <X11/Xutil.h>             /* shape.h の前に必要 */
    8	#include <X11/extensions/shape.h>  /* Shape Extension    */
    9	
   10	
   11	/*
   12	 * bounding 領域および clip 領域を表す X11 形式のビットマップデータ
   13	 */
   14	#include "btn_bd.h"
   15	#include "btn_cl.h"
   16	
   17	
   18	#define WIN_X 100
   19	#define WIN_Y 100
   20	
   21	#define SPC_X  25
   22	#define SPC_Y  25
   23	
   24	#define WIN_W ( btn_bd_width  + SPC_X * 2 )
   25	#define WIN_H ( btn_bd_height + SPC_Y * 2 )
   26	
   27	
   28	int 
   29	main( void )
   30	{
   31		Display* dpy;
   32		int      screen;
   33	
   34		Window   base;
   35		Window   button;
   36		GC       gc;
   37	
   38		Pixmap   pixmap_bounding;   /* bounding 領域を決定するビットマップ */
   39		Pixmap   pixmap_clip;       /* clip     領域を決定するビットマップ */
   40		int      event_no_base;     /* ShapeNotify イベントの番号 */
   41		int      error_no_base;     /* Shape Extension で発生するエラーの最初の番号 */
   42	
   43		unsigned long white, black, blue, red;
   44	
   45	
   46		dpy    = XOpenDisplay( NULL );
   47		screen = DefaultScreen( dpy );
   48	
   49	
   50		/*
   51		 * 接続した X サーバが、Shape Extension をサポートしているか
   52		 * どうかを調べる。
   53		 */
   54		if ( ! XShapeQueryExtension( dpy, &event_no_base, &error_no_base ) ) {
   55			fprintf( stderr, "Shape extension is not available\n" );
   56			XCloseDisplay( dpy );
   57			return 1;
   58		}
   59	
   60	
   61		/*
   62		 * 色設定
   63		 */
   64		{
   65			XColor   color, exact; 
   66			Colormap cmap;
   67	
   68			white  = WhitePixel( dpy, screen );
   69			black  = BlackPixel( dpy, screen );
   70	
   71			cmap   = DefaultColormap( dpy, screen );
   72	
   73			XAllocNamedColor( dpy, cmap, "blue", &color, &exact );
   74			blue = color.pixel;
   75	
   76			XAllocNamedColor( dpy, cmap, "red",  &color, &exact );
   77			red  = color.pixel;
   78		}
   79	
   80	
   81		/*
   82		 * Window 作成
   83		 */
   84		{
   85			/*
   86			 * base Window を作成する。
   87			 */
   88			base = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ),
   89						    WIN_X, WIN_Y,
   90						    WIN_W, WIN_H,
   91						    0, black, blue );
   92			XStoreName( dpy, base, "Button" );
   93		
   94	
   95			/*
   96			 * bounding ビットマップの幅と高さを使って button Window を作成する。
   97			 */
   98			button = XCreateSimpleWindow( dpy, base, 
   99						      SPC_X, SPC_Y,
  100						      btn_bd_width, btn_bd_height,
  101						      0, black, white );
  102	
  103			gc = XCreateGC( dpy, button, 0, NULL );
  104			XSetBackground( dpy, gc, white );
  105		}
  106	
  107	
  108		/*
  109		 * bounding 領域および clip 領域の設定
  110		 */
  111		{
  112			/*
  113			 * bounding 領域および clip 領域を表現するビットマップを作成する。
  114			 */
  115			pixmap_bounding = XCreateBitmapFromData( 
  116				dpy, button,
  117				( char* )btn_bd_bits,
  118				btn_bd_width, btn_bd_height );
  119	
  120			pixmap_clip     = XCreateBitmapFromData(
  121				dpy, button,
  122				( char* )btn_cl_bits,
  123				btn_cl_width, btn_cl_height );
  124	
  125			/*
  126			 * bounding 領域および clip 領域を設定する。
  127			 */
  128			XShapeCombineMask( dpy, button, ShapeBounding, 
  129					   0, 0, pixmap_bounding, ShapeSet );
  130	
  131			XShapeCombineMask( dpy, button, ShapeClip,     
  132					   0, 0, pixmap_clip,     ShapeSet );
  133		}
  134	
  135	
  136		XSelectInput( dpy, base,   ButtonPressMask );
  137		XSelectInput( dpy, button, ButtonPressMask );
  138	
  139		XMapWindow( dpy, base );
  140		XMapSubwindows( dpy, base );
  141	
  142	
  143		/*
  144		 * 真中の Window 内でマウスの左ボタンをクリックする度に、
  145		 * 表示色を 赤<==>白 で切替える。
  146		 * Window に関係無く、右ボタンをクリックすると終了する。
  147		 */
  148		while ( 1 ) {
  149			static XEvent event;
  150			static char flag = 0;
  151	
  152			XNextEvent( dpy, &event );
  153	
  154			switch ( event.type ) {
  155			case ButtonPress:
  156				switch ( event.xbutton.button ) {
  157				case Button1:  /* Left   Button */
  158					if ( event.xbutton.window == button ) {
  159						if ( ! flag ) {
  160							XSetForeground( dpy, gc, red );
  161							flag ++;
  162						}
  163						else {
  164							XSetForeground( dpy, gc, white );
  165							flag --;
  166						}
  167	
  168						XFillRectangle( dpy, button, gc, 
  169							0, 0, btn_bd_width, btn_bd_height );
  170					}
  171					break;
  172	
  173				case Button3:  /* Right  Button */
  174					XFreeGC( dpy, gc );
  175					XDestroyWindow( dpy, base );
  176					XCloseDisplay( dpy );
  177					return 0;
  178				}
  179	
  180			default:
  181				break;
  182			}
  183		}
  184	}
  185	
  186	
  187	/* End of xshape.c */

--- btn_bd.h ---

    1   #define btn_bd_width 101
    2   #define btn_bd_height 51
    3   static unsigned char btn_bd_bits[] = {
    4      0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00,
    5      0xe0, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
    6      0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    7      0x7f, 0x00, 0xe0, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    8      0xff, 0xff, 0x01, 0xe0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    9      0xff, 0xff, 0xff, 0x07, 0xe0, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
   10      0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
   11      0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x80, 0xff, 0xff, 0xff, 0xff,
   12      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0xc0, 0xff, 0xff, 0xff,
   13      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xe0, 0xff, 0xff,
   14      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xf0, 0xff,
   15      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xf0,
   16      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1,
   17      0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   18      0xe3, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   19      0xff, 0xe3, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   20      0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   21      0xff, 0xff, 0xff, 0xe7, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   22      0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   23      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   24      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   25      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   26      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   27      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   28      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   29      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   30      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   31      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   32      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   33      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   34      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   35      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   36      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   37      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   38      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   39      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   40      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff,
   41      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xfc,
   42      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7,
   43      0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   44      0xe7, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   45      0xff, 0xe3, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   46      0xff, 0xff, 0xe3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   47      0xff, 0xff, 0xff, 0xe1, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   48      0xff, 0xff, 0xff, 0xff, 0xe1, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   49      0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
   50      0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0x80, 0xff, 0xff, 0xff, 0xff,
   51      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x80, 0xff, 0xff, 0xff,
   52      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x00, 0xfe, 0xff,
   53      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0x00, 0xfc,
   54      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xe0, 0x00,
   55      0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xe0,
   56      0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00,
   57      0xe0, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
   58      0x00, 0xe0, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   59      0x07, 0x00, 0xe0};

--- btn_cl.h ---

    1   #define btn_cl_width 101
    2   #define btn_cl_height 51
    3   static unsigned char btn_cl_bits[] = {
    4      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    5      0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    6      0x00, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    7      0x1f, 0x00, 0xe0, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    8      0xff, 0x3f, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    9      0xff, 0xff, 0x7f, 0x00, 0xe0, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
   10      0xff, 0xff, 0xff, 0xff, 0x01, 0xe0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff,
   11      0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xe0, 0x00, 0xfe, 0xff, 0xff, 0xff,
   12      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0x80, 0xff, 0xff, 0xff,
   13      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x80, 0xff, 0xff,
   14      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0xc0, 0xff,
   15      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xe0,
   16      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
   17      0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   18      0xe1, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   19      0xff, 0xe1, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   20      0xff, 0xff, 0xe3, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   21      0xff, 0xff, 0xff, 0xe3, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   22      0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   23      0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff,
   24      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff,
   25      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff,
   26      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff,
   27      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff,
   28      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc,
   29      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7,
   30      0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   31      0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   32      0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   33      0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   34      0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   35      0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   36      0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff,
   37      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff, 0xff,
   38      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff, 0xff,
   39      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff, 0xff,
   40      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfc, 0xff,
   41      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf8,
   42      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3,
   43      0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   44      0xe3, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   45      0xff, 0xe1, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   46      0xff, 0xff, 0xe1, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   47      0xff, 0xff, 0xff, 0xe0, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   48      0xff, 0xff, 0xff, 0x7f, 0xe0, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   49      0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff,
   50      0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0x00, 0xfe, 0xff, 0xff, 0xff,
   51      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xe0, 0x00, 0xfc, 0xff, 0xff,
   52      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xe0, 0x00, 0xf0, 0xff,
   53      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xe0, 0x00, 0xc0,
   54      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xe0, 0x00,
   55      0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xe0,
   56      0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
   57      0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   58      0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   59      0x00, 0x00, 0xe0};

○ サンプルプログラムの説明

では、サンプルプログラムについて説明していきます。

  • 8 行目

    SHAPE extension を使用するために必要な <X11/extensions/shape.h> をインクルードしています。

  • 14 〜 15 行目

    bounding 領域および clip 領域を表す X11 形式のビットマップデータをインクルード しています。X11 形式のビットマップデータは C 言語のヘッダファイルの形式であるため、 この様にして使用します。

  • 24 〜 25 行目

    ビットマップデータの中で定義されているビットマップの幅と高さを使って、 ボタンを表示するウィンドウの幅を決めています。

  • 38 〜 41 行目

    SHAPE extension を使う際に必要となる bounding region および clip region を格納するための Pixmap と、その他の変数を定義しています。event_no_base と error_no_base については後程説明します。

  • 50 〜 58 行目

    X サーバに接続した直後に、まず SHAPE extension をサポートしているかどうかを XShapeQueryExtension() を使って問い合わせています。サポートしていない場合は、 プログラムを終了しています。

      Bool XShapeQueryExtension( Display* display,
                                 int*     event_basep,
                                 int*     error_basep 
                               );
    
      event_basep : ShapeNotify イベントを表す番号が格納される
      error_basep : SHAPE extension で発生するエラー番号の最初の番号が格納される
    
    

    SHAPE extension がサポートされている場合は True、サポートされていない場合は False を返します。サポートされている場合は event_basep に ShapeNotify イベントを表す番号が格納されます。また、error_basep に、SHAPE extension で発生するエラー番号の最初の番号が格納されます。

    ShapeNotify イベントについては後述します。

  • 61 〜 78 行目

    ベースとなるウィンドウとボタンウィンドウの表示色となる、青、赤、白、黒 のピクセル値を取得しています。

  • 81 〜 105 行目

    ベースウィンドウとボタンウィンドウを作成しています。ボタンウィンドウは、 ビットマップデータに定義されている幅と高さを使って作成しています。 また、ボタンウィンドウの表示色を変える際に使用する GC を作成して、 最初の表示色を設定しています。

    ベースウィンドウの作成で使用している XStoreName() は、ウィンドウマネージャに対して タイトルバーに表示する文字列を通知する関数です。ここまでに説明した記憶が無いので ここであらためて。

       XStoreName( Display* display, Window win, char* name );
    
       name : タイトルバーに表示する文字列
    
    

  • 108 〜 133 行目

    ここが本題です。作成したばかりのウィンドウの bounding region と clip region はデフォルト状態ですが、これを変更します。 まず、ビットマップデータを使って region の指定に使用する Pixmap を XCreateBitmapFromData() を使って作成します。XCreateBitmapFromData() については、 Appendix ( 付録 ) で説明していますので、 そちらを参照して下さい。

    作成した Pixmap を、XShapeCombineMask() を使って bounding region および clip region として設定します。

      XShapeCombineMask( Display* display,
                         Window   dst,
                         int      dst_kind, x_off, y_off,
                         Pixmap   src,
                         int      op
                       );
    
      dst          : region を設定する対象となる Window
    
      dst_kind     : bounding region を設定する場合は ShapeBounding
                     clip region     を設定する場合は ShapeClip を指定
    
      x_off, y_off : src をその幅と高さで表される四角形と考えた場合に、左上の角を
                     dst 上のどの位置において設定するかを指定
    
      src          : region の設定に使用する Pixmap
                     デフォルトに戻す場合は None を指定する
    
      op           : src と dst による region 決定の演算方法を指定
    
    

    op には ShapeSet、ShapeUnion、ShapeIntersect、ShapeSubtract、ShapeInvert が設定できます。

    • ShapeSet

      src を dst_kind で指定した region として設定する

    • ShapeUnion

      dst および src を合わせた領域を、dst_kind で指定した region として設定する

    • ShapeIntersect

      dst および src の重なる領域を、dst_kind で指定した region として設定する

    • ShapeSubtract

      dst から src を除いた領域を、dst_kind で指定した region として設定する

    • ShapeInvert

      src から dst を除いた領域を、dst_kind で指定した region として設定する

    ちなみに xshape.c で ShapeSet の代わりに ShapeUnion および ShapeSubtract を指定した場合の表示は以下の様になります。 ShapeIntersect と ShapeInvert は各自で何か作って表示してみて下さい ! ( 自分でやるのが面倒だっただけです。。。m(__)m )

    --- ShapeUnion ---

    018union.jpg

    --- ShapeSubtract ---

    018subtract.jpg

    ↑白い箇所がボタンウィンドウなので、ShapeSubtract の場合面白いことになってます。 4 つのウィンドウがあるかの様ですね!

  • 143 〜 183 行目

    イベントループです。マウスの左ボタンをクリックした場合、ボタンウィンドウであれば ( 158 行目 ) flag の値によって表示色を GC に設定して、168 行目の XFillRectangle() でボタンウィンドウを塗りつぶしています。XFillRectangle() で長方形領域を塗りつぶしても、 表示される領域はこれまでと変わりません。

    マウスの右ボタンをクリックした場合は、リソースを解放して終了します。

以上で xshape.c の解説は終わりです。 これを機に、すごく変わった形のアプリケーションでも作ってみてはいかがでしょう?

○ SHAPE extension で使用できるその他の関数

ここでは SHAPE extension で使用できるその他の関数のうちのいくつかについて説明します。

  • XShapeQueryVersion()

    SHAPE extension のバージョンを取得します。 実行すると、major および minor に指定した変数に番号が格納されます。

      Status XShapeQueryVersion( Display* display, int* major, int* minor );
    
      major : メジャー番号
      minor : マイナー番号
    
    

  • XShapeCombineRectangles()

    XRectangle の配列を使って、region の設定を行います。

      XShapeCombineRectangles( Display*     display,
                               Window       dst,
                               int          dst_kind, x_off, y_off,
                               XRectangles* rectangles,
                               int          n_rects, op, ordering
                             );
    
      dst          : region を設定する対象となる Window
    
      dst_kind     : bounding region を設定する場合は ShapeBounding
                     clip region     を設定する場合は ShapeClip を指定
    
      x_off, y_off : rectangles による region の設定を、
                     dst 上のどの位置において設定するかを指定
    
      rectangles   : region の設定に使用する領域を XRectangle の配列で指定する
    
      n_rects      : rectangles に指定した XRectangle の数
      op           : src と dst による region 決定の演算方法を指定(XShapeCombineMask()と同じ)
    
      ordering     : rectangles に指定した XRectangle の並び方を指定
    
    

    ordering には Expose イベント で説明した XSetClipRectangles() の ordering に使用できる定数を使います。

  • XShapeCombineShape()

    Pixmap ではなく、Window を使って region の設定を行います。

      XShapeCombineShape( Display* display,
                          Window   dst,
                          int      dst_kind, x_off, y_off,
                          Window   src,
                          int      src_kind, op
                        );
    
      dst          : region を設定する対象となる Window
    
      dst_kind     : bounding region を設定する場合は ShapeBounding
                     clip region     を設定する場合は ShapeClip を指定
    
      x_off, y_off : src をその幅と高さで表される四角形と考えた場合に、左上の角を
                     dst 上のどの位置において設定するかを指定
    
      src          : region の設定に使用する Window
    
      src_kind     : bounding region を使用する場合は ShapeBounding
                     clip region     を使用する場合は ShapeClip を指定
    
      op           : src と dst による region 決定の演算方法を指定(XShapeCombineMask と同じ)
    
    

  • XShapeOffsetShape()

    現在設定されている region を指定量だけ移動させます。

      XShapeOffsetShape( Display* display, Window dst, int dst_kind, int x_off, int y_off );
    
      dst_kind     : bounding region を設定する場合は ShapeBounding
                     clip region     を設定する場合は ShapeClip を指定
    
      x_off, y_off : region の移動量を X および Y 座標それぞれについて指定
    
    

  • XShapeQueryExtents()

    現在設定されている bounding region および clip region についての情報を取得します。

      Status XShapeQueryExtents( Display* display, 
                                 Window   win,
                                 Bool     *bounding,
                                 int      *x_bounding, *y_bounding, *w_bounding, *h_bounding,
                                 Bool     *clip,
                                 int      *x_clip, *y_clip, *w_clip, *h_clip
                               );
    
      bounding               : bounding region が設定されている場合に True が格納される
      x_bounding, y_bounding : bounding region の左上角の座標が格納される
      w_bounding, h_bounding : bounding region の幅と高さが格納される
    
      clip                   : clip region が設定されている場合に True が格納される
      x_clip, y_clip         : clip region の左上角の座標が格納される
      w_clip, h_clip         : clip region の幅と高さが格納される
    
    

  • XShapeSelectInput()

    bounding region もしくは clip region に変化があった場合に、ShapeNotify イベントを送ってもらう様に X サーバに通知します。

      XShapeSelectInput( Display* display, Window win, unsigned long mask );
    
      mask : ShapeNotifyMask を指定
    
    

    ShapeNotify イベント構造体は以下の様に定義されています。

      typedef struct {
        int           type;            /* イベントの種類 */
        unsigned long serial;          /* サーバが処理した最後のリクエスト番号 */
        Bool          send_event;      /* クライアントから送られたイベントなら True */
        Display*      display;         /* イベントが読み込まれたdisplay */
        Window        window;          /* イベントが起こった window のID */
        int           kind;            /* ShapeBounding もしくは ShapeClip */
        int           x, y;            /* 新しい region の左上角の座標 */
        unsigned      width, height;   /* 新しい region の幅と高さ */
        Time          time;            /* region が変更された時刻 */
        Bool          shaped;          /* region が存在する場合は True */
      } XShapeEvent;
    
    

  • XShapeInputSelected()

    ShapeNotify イベントを送ってもらう様に XShapeSelectInput() で指定した場合に ShapeNotifyMask を、そうでない場合には 0 を返します。

      unsigned long XShapeInputSelected( Display* display, Window win );
    
    

  • XShapeGetRectangles()

    現在の bounding region あるいは clip region を表現する XRectangle の配列を取得します。 XShapeCombineRectangles() の逆操作の様なものです。

      XRectangle* XShapeGetRectangles( Display*  display,
                                       Window    win,
                                       int       kind,
                                       int*      count, 
                                       int*      ordering
                                     );
    
      kind     : bounding region を指定する場合は ShapeBounding
                 clip region     を指定する場合は ShapeClip を指定
    
      count    : 返却値に設定されている XRectangle の数
    
      ordering : 返却値に設定されている XRectangle の並び方
                 XSetClipRectangles() の ordering に使用できる定数