実践Linux                 TOPへ  Cプログラミング目次へ

X11プログラミング  2009年5月更新


●X11汎用Makefile
プログラムソースをtest.cで保存して、Makefileを以下の内容で準備し、makeを実行する。
字下げはTabキーで行うこと。

INCLUDE = /usr/X11R6/include/X11
LIB = /usr/X11R6/lib
CC = gcc
CFLAGS = -lX11 -lpthread
TARGETS = test
OBJ = ${SRC:.c=.o}
SRC = test.c

$(TARGETS):${OBJ}
  ${CC} -I ${INCLUDE} -L ${LIB} ${CFLAGS} ${OBJ} -o ${TARGETS}

${OBJ}:${SRC}
  ${CC} ${SRC} -c -o ${OBJ}

clean:
  rm -f *.o $(TARGETS)


プログラムのダウンロード(X-program.tar.gz)

●ウィンドマネージャーの介入なし



#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main(void)
{
Display *d;
Window wr, w1, w2;
GC gc, gc1, gc2;
XSetWindowAttributes attr;
unsigned long black,white;

d=XOpenDisplay(NULL);

black=BlackPixel(d,0);
white=WhitePixel(d,0);

wr=XCreateSimpleWindow(d,RootWindow(d,0),100,50,800,530,1,black,white);  親ウィンドの生成
w1=XCreateSimpleWindow(d,wr,10,10,780,400,1,black,white);  子ウィンドの生成
w2=XCreateSimpleWindow(d,wr,10,410,780,80,1,black,black);

attr.override_redirect=True;
XChangeWindowAttributes(d,wr,CWOverrideRedirect,&attr);

XMapWindow(d,wr);  親ウィンドのマップ(ディスプレイ上に写像して可視状態にする)
XMapSubwindows(d,wr);  子ウィンド(w1、w2)のマップ

gc=XCreateGC(d,wr,0,0);  各ウィンドに対するGC(このあとここに描画色や描画フォントなどの設定を行っていく)の生成
gc1=XCreateGC(d,w1,0,0);
gc2=XCreateGC(d,w2,0,0);

……………
XDrawString(d,wr,gc,500,515,"test",4);
XFlush(d);
sleep(10);
return(0);
}


●ウィンドマネージャー付き



上のmainの中を手直しする。
Display *d;
Window wr, w1, w2;
GC gc, gc1, gc2;
XEvent event;
unsigned long black,white;

d=XOpenDisplay(NULL);

black=BlackPixel(d,0);
white=WhitePixel(d,0);

wr=XCreateSimpleWindow(d,RootWindow(d,0),100,50,800,530,1,black,white);
w1=XCreateSimpleWindow(d,wr,10,10,780,400,1,black,white);
w2=XCreateSimpleWindow(d,wr,10,410,780,80,1,black,black);

XSelectInput(d,wr,ExposureMask);  Exposeイベントを設定

XMapWindow(d,wr);
XMapSubwindows(d,wr);

gc=XCreateGC(d,wr,0,0);
gc1=XCreateGC(d,w1,0,0);
gc2=XCreateGC(d,w2,0,0);

while(1)
{
XNextEvent(d,&event);
switch(event.type)
{
case Expose:
XDrawString(d,wr,gc,500,515,"test",4);
XFlush(d);
……………  その他のイベント
}
}


●GCへのフォントや色の設定
GC gc1, gc2;
Font f1,f2;
unsigned long black,white;  白と黒の設定は簡単な方法で行えるので別に定義
Colormap cmap;
XColor c0,red,green;

……………
gc1=XCreateGC(d,w1,0,0);
gc2=XCreateGC(d,w2,0,0);

f1=XLoadFont(d,"variable");  ………………………フォントの読み込み
f2=XLoadFont(d,"-urw-helvetica-bold-r-normal--42-401-75-75-p-234-iso8859-1");
XSetFont(d,gc1,f1);  …………………………………各GCにフォントの設定
XSetFont(d,gc2,f2);

black=BlackPixel(d,0);  ………………………………白と黒
white=WhitePixel(d,0);
cmap=DefaultColormap(d,0);  …………………………その他の色
XAllocNamedColor(d,cmap,"red",&red,&c0);
XAllocNamedColor(d,cmap,"green",&green,&c0);
XSetForeground(d,gc1,white);  ………………………各GCに前面色の設定
XSetForeground(d,gc2,green.pixel);

XDrawString(d,w1,gc1,500,515,"test",4);
……………
XFlush(d);

●ピクセルマップを使った表示(ちらつきをなくす)
Display *d;
Window w1, w2;
GC gc1, gc2;
Pixmap p1, p2;

……………
p1=XCreatePixmap(d,w1,780,400,DefaultDepth(d,0));
p2=XCreatePixmap(d,w2,780,80,DefaultDepth(d,0));

……………
XDrawLine(d,p1,gc1,0,0,100,100);  いったんピクセルマップp1に描画していく
……………
XCopyArea(d,p1,w1,gc1,0,0,780,400,0,0);  それをウィンドw1にコピー

XFillRectangle(d,p2,gc2,0,0,780,80);
XDrawString(d,p2,gc2,100,60,s,strlen(s));
XCopyArea(d,p2,w2,gc2,0,0,780,80,0,0);

XFlush(d);

XCopyAreaの代わりに、XSetWindowBackgroundPixmapでピクセルマップをウィンド本体の背景として設定してもよい。
XSetWindowBackgroundPixmap(d,w1,p1);
XClearWindow(d,w1);
また、ピクセルマップにはウィンドのように初期化やクリアの機能がないため、これらはXSetForegroundとXFillRectangle関数によって行う。
XSetForeground(d,gc2,white);
XFillRectangle(d,p2,gc2,0,0,780,80);
XCopyArea(d,p2,w2,gc2,0,0,780,80,0,0);


●ビットマップ画像を表示する  XImageによる表示方法



#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include "zu.h"

int main(void)
{
Display *d;
Window wr;
GC gc;
XImage im;
XColor col[8][8][8];
Colormap cmap;
XEvent event;
int l,m,n;

d=XOpenDisplay(NULL);
cmap=DefaultColormap(d,0);
for(l=0;l<8;l++)
{
for(m=0;m<8;m++)
{
for(n=0;n<8;n++)
{
col[l][m][n].red=65535-(7-l)*65535/7;
col[l][m][n].green=65535-(7-m)*65535/7;
col[l][m][n].blue=65535-(7-n)*65535/7;
XAllocColor(d,cmap,&col[l][m][n]);
}
}
}

wr=XCreateSimpleWindow(d,RootWindow(d,0),100,50,640,400,1,col[0][0][0].pixel,col[7][7][7].pixel);
XStoreName(d,wr,"show bitmap");
XSelectInput(d,wr,ExposureMask);
XMapWindow(d,wr);
gc=XCreateGC(d,wr,0,0);

XSetForeground(d,gc,col[0][7][0].pixel);
XSetBackground(d,gc,col[7][0][0].pixel);

im.format=XYBitmap;
im.width=640;
im.height=400;
im.xoffset=0;
im.byte_order=LSBFirst;
im.bitmap_unit=8;
im.bitmap_bit_order=LSBFirst;
im.bitmap_pad=8;
im.depth=1;
im.bytes_per_line=(640+7)>>3;
im.data=zu_bits; //読み込み

while(1)
{
XNextEvent(d,&event);
switch(event.type)
{
case Expose:
XRaiseWindow(d,wr);
XPutImage(d,wr,gc,&im,0,0,0,0,640,400);

XFlush(d);
}
}
}

zu.hファイル  プログラムと同じディレクトリに置いておく。
#define zu_width 640
#define zu_height 400
static unsigned char zu_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

ビットマップファイルを作成するには
 # bitmap -size 50x50
 この中身を見るには、 # cat test.bmp


●GIMPで作成したVWDフォーマット画像の表示  XImage構造体を使う



#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XWDFile.h>
#include <stdio.h>

typedef struct struct_imElement{ XImage *im; int width; int height; } imElement;

main(void)
{
Display *d;
Window wr;
GC gc;
Pixmap pr;
XEvent event;
void XWDView(Display *d, char name[], imElement *im);
imElement im1;

d=XOpenDisplay(NULL);

wr=XCreateSimpleWindow(d,RootWindow(d,0),0,0,800,600,0,0,0);
XStoreName(d, wr, “test”);
XSelectInput(d,wr,ExposureMask);
XMapWindow(d,wr);
gc=XCreateGC(d,wr,0,0);
pr=XCreatePixmap(d,wr,800,600,DefaultDepth(d,0));

XSetForeground(d,gc,BlackPixel(d,0));
XFillRectangle(d,pr,gc,0,0,800,600);

XWDView(d, “test.xwd”, &im1);  ←サブ関数で画像ファイルを読み込みimにセットする
XPutImage(d,pr,gc,im1.im,0,0,100,50,im1.width,im1.height);  ←XImage構造体imの(prへの)描画

while(1)
{
XNextEvent(d,&event);
switch(event.type)
{
case Expose:
XCopyArea(d,pr,wr,gc,0,0,800,600,0,0);
XFlush(d);
}
}
}

/////////////////////////////////////////////////////

void XWDView(Display *d, char name[], imElement *im)
{
XWDFileHeader fh;  ←XWDファイルのヘッダー部の構造体
int change(unsigned int val);

FILE *fp;
unsigned char buff[3*800*600];
int i, flg;
int r0,r1,r2;  ←ディスプレイ設定が16ビットの時使う

if((fp=fopen(name,”r”)) == NULL)
{
printf(“can not open file!”);
exit(0);
}
flg=fread(&fh,sizeof(fh),1,fp);  ←VWDファイルのヘッダー部の読み込み
fh.window_width=change(fh.window_width);  ←fh.****の値は32ビットデータが8ビットずつの単位で逆になっているので元に戻す。
fh.window_height=change(fh.window_height);
fh.bits_per_pixel=change(fh.bits_per_pixel);
fh.bytes_per_line=change(fh.bytes_per_line);
flg=fread(buff,fh.bits_per_pixel/8,fh.window_width*fh.window_height,fp);  ←VWDファイルの画像データ部の読み込み
fclose(fp);

im->width=fh.window_width;
im->height=fh.window_height;

im->im=XCreateImage(d,DefaultVisual(d,0),DefaultDepth(d,0),ZPixmap,0,0,im->width,im->height,32,0);  ←XImage構造体の生成

if(DefaultDepth(d,0) == 16)     ←ディスプレイ設定が16ビットの時、画像データの変換
{
for(i=0;i<im->width*im->height;i++)
{
r0=31*buff[3*i+0]/255;
r1=31*buff[3*i+1]/255;
r2=31*buff[3*i+2]/255;
buff[3*i+0]=0x00;
buff[3*i+1]=r0<<3 | r1>>2;
buff[3*i+2]=(r1 & 0x07)<<6 | r2;
}
}

im->im->data=(char *)buff;  ←XImage構造体に画像データを代入
im->im->xoffset=0;
im->im->byte_order=MSBFirst;
im->im->bitmap_unit=32;
im->im->bitmap_bit_order=MSBFirst;
im->im->bytes_per_line=fh.bytes_per_line;
im->im->bits_per_pixel=fh.bits_per_pixel;
}

//////////////////////////////////////////////////////////////////////////////////

int change(unsigned int val)
{
val=(val<<24)+(val<<8 & 0xff0000)+(val>>8 & 0xff00)+(val>>24);
return val;
}


TOPへ  Cプログラミング目次へ