QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1123|回复: 6

Xwindows开发学习

[复制链接]
发表于 2005-3-16 22:15:11 | 显示全部楼层 |阅读模式
Xwindows开发学习
Sunday, March 13th, 2005

作者: Komtas 无双 发表于wsue.org loveunix.net
转载请注明出处

昨天想写一个支持xim的客户端

不过找现成的例子来都试不出输入法

没法 从头开始学习xwindows编程吧

开始编程前先要有一个好的开发工具 可以快速的查找函数与宏定义及结构定义
我推荐vim

然后是要随时准备看man 基本上x开发不难 但是看man理解每个函数
那对以后的开发会更快

下面先开始vim相关的配置
1 创建/usr/include目录下的定义索引
cd /usr/include
ctags *
2 创建 /usr/include/X11目录下的定义索引
cd /usr/include/X11
ctags *

3 编辑你的~/.vimrc

vi ~/.vimrc 增加下面两行
set path+=.,./include,../include,/usr/include,/usr/include/**,/usr/X11R6/include,/usr/local/include
set tags=./tags,../tags,../../tags,/usr/include/tags,/usr/include/X11/tags

4 快速的使用vim的一些技巧
在x开发中 可能会看到很多结构或是宏定义
这时可以在你想查找的定义上使用
ctrl-w-]键跳转到它的定义处
:q退出定义窗口
ctrl-P 单词完成

快速的make与改错
在vim下输入:
:mak
然后使用
cn或cp浏览错误

编译
gcc -L/usr/X11R6/lib -lX11 filename.c -o filename.o

第一个程序
hello world

每个Xwindows程序都由三个部分组成
1 Desplay 这个就是X服务器
2 Win 程序的窗口 可能有一个或多个
3 gc […]
 楼主| 发表于 2005-3-16 22:15:54 | 显示全部楼层
Xwindows开发学习

第一个程序
hello world

每个Xwindows程序都由三个部分组成
1 Desplay 这个就是X服务器
2 Win 程序的窗口 可能有一个或多个
3 gc 图形上下文 如果你想在程序窗口中输出内容时 你就需要到这个东西

每个程序的流程就是
1 打开显示
2 创建窗口
3 创建GC
4 选择窗口关心的事件
5 映射窗口 这时在屏幕上显示程序界面
6 进程事件循环读事件并处理
下面就是hello world的流程

[code:1]
#include ≶X11/Xlib.h>
#include ≶X11/Xutil.h>
#include ≶X11/Xos.h>
#include ≶X11/Xatom.h>

#define DUMP_ERR printf

int main()
{
Display *display;
int screennum;
int width;
int height;

const char *strdraw = “hello world”;

Window win;
GC gc;
//打开显示 没有指明打开哪个显示时使用环境变量中的DESPLAY
display = XOpenDisplay(NULL);
if( !display ){
DUMP_ERR(”call XOpenDisplay(%s) fail\n”,XDisplayName(NULL));
return 1;
}

//得到系统当前的屏幕 (如果使用虚拟屏幕的话 一般会有几个)
// get default screen
screennum = DefaultScreen(display);
//根据屏幕的大小决定窗口的大小
width = DisplayWidth(display,screennum)/4;
height = DisplayHeight(display,screennum)/4;

//创建窗口
// create window
win = XCreateSimpleWindow(display,
RootWindow(display,screennum),
0,0,width,height,3,
BlackPixel(display,screennum),
WhitePixel(display,screennum));

//选择窗口关心的事件
// select event
XSelectInput(display,win,
ExposureMask|KeyPressMask
|ButtonPressMask|StructureNotifyMask);

//创建GC(图形上下文)
// create gc
{
unsigned long valuemask = 0;
XGCValues values;
gc = XCreateGC(display,win,valuemask,&values);
}

// 映射窗口 只有map后窗口才会在屏幕上显示
// show window
XMapWindow(display,win);

//进入事件循环
// event loop
while(1){
XEvent event;
XNextEvent(display,&event); // 读一个事件

switch(event.type){
case Expose: // expose window 显示事件
if( event.xexpose.count != 0) break;
XDrawString(display,win,gc,10,10,
strdraw,strlen(strdraw));
break;

// 按键事件
case ButtonPress:
case KeyPress:
XFreeGC(display,gc);
XCloseWindow(win);
XCloseDisplay(display);
return 0;
default:
break;
}
}
}
[/code:1]
回复

使用道具 举报

 楼主| 发表于 2005-3-16 22:16:17 | 显示全部楼层
Xwindows开发学习

上面是一个最基本的例子 基本上除了hello world外什么事也不做
下面开始介绍在X上画图的例子
上面说过GC 画图就是在gc上输出内容
每个gc都有属性 可以通过XChangeGC修改或是通过其它修改gc性能的函数

XSetLineAttributes修改
这两个的效果是一样的
[code:1]
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>

#define DUMP_ERR printf

static void draw(Display *display,Window win,GC gc,int width,int height);

int main()
{
Display *display;
int screennum;
int width;
int height;
Atom protocols;

const char *strdraw = “hello world”;

Window win;
GC gc;

display = XOpenDisplay(NULL);
if( !display ){
DUMP_ERR(”call XOpenDisplay(%s) fail\n”,XDisplayName(NULL));
return 1;
}

// get default screen
screennum = DefaultScreen(display);
width = DisplayWidth(display,screennum)/2;
height = DisplayHeight(display,screennum)/2;

// create window
win = XCreateSimpleWindow(display,
RootWindow(display,screennum),
0,0,width,height,3,
BlackPixel(display,screennum),
WhitePixel(display,screennum));

//增加这个代码是捕获程序退出事件
protocols = XInternAtom(display, “WM_DELETE_WINDOW”, True);
XSetWMProtocols(display, win, &protocols, 1);

// select event
XSelectInput(display,win,
ExposureMask|KeyPressMask
|ButtonPressMask|StructureNotifyMask);

// create gc
{
unsigned long valuemask = 0;
XGCValues values;
gc = XCreateGC(display,win,valuemask,&values);
}

// show window
XMapWindow(display,win);

// event loop
while(1){
XEvent event;
XNextEvent(display,&event);

switch(event.type){
case Expose: // expose window
if( event.xexpose.count != 0) break;
draw(display,win,gc,width,height);
//XDrawString(display,win,gc,10,10,
//strdraw,strlen(strdraw));
break;

case ConfigureNotify: // when the window’s size change
width = event.xconfigure.width;
height = event.xconfigure.height;
break;
case ClientMessage :
if(event.xclient.data.l[0] == protocols){
DUMP_ERR(”recv destroy notify\n”);
XFreeGC(display,gc);
XDestroyWindow(display, win);
XCloseDisplay(display);
}
return 0;

default:
break;
}
}
}
[/code:1]
// 使用changeGC修改属性的代码 只有valuemask被设置的属性才会根据XCGValues里面的值进行修改
static void set_gc_values(Display *display,GC gc)
{
XGCValues values;
values.line_width = 2;
values.line_style = LineSolid;
values.cap_style = CapRound;
values.join_style = JoinRound;

XChangeGC(display,gc,GCLineWidth|GCLineStyle,//|GCCapStyle|GCFillStyle,
&values);
}

// 画画的代码
static void draw(Display *display,Window win,GC gc,int width,int height)
{
int i,x,y;
unsigned int ling_width = 0;
int line_style = LineSolid;// 是实线
int cap_style = CapRound; // 端点类型是圆的
int join_style = JoinRound;// 接点类型是圆的

XPoint points[5] = {
{400,200},
{600,200},
{450,300},
{500,150},
{550,300},
};

// draw point
for(i = 0;i< width;i++)
XDrawPoint(display,win,gc,i,10);

// draw line
y = 30;
for(i = 0;i<10;i+=2){
// int XSetLineAttributes(Display *display, GC gc, unsigned int
// line_width, int line_style, int cap_style, int join_style);
XSetLineAttributes(display,gc,i,line_style,cap_style,join_style);
// int XDrawLine(Display *display, Drawable d, GC gc, int x1, int y1, int
//x2, int y2);
XDrawLine(display,win,gc,10,y,width-10,y);
y += 20;
}

set_gc_values(display,gc);
XDrawRectangle(display,win,gc,10,y,50,50);
XDrawRectangle(display,win,gc,100,y,200,200);

XDrawArc(display,win,gc,100,y,200,200,0,90*64);
XFillArc(display,win,gc,100,y,200,200,90*64,120*64);

XFillPolygon(display,win,gc,points,5,Complex,EvenOddRule);
}
回复

使用道具 举报

 楼主| 发表于 2005-3-16 22:16:40 | 显示全部楼层
Xwindows开发学习

中文的输出

在X中直接支持中文的输出 不需要特殊的处理
但是
程序中要先使用
setlocale来设置当前locale 然后使用XSupportsLocale检查是不是支持当前locale
如果支持 那么使用
XCreateFontSet创建字体集 包括需要显示的内容的字体
后面就可以使用XmbDrawString或XwcDrawString了

[code:1]
#include <stdio.h>
#include <locale.h>

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

#define DUMP_ERR printf

static void draw(Display *display,Window win,XFontSet fontset,GC gc);

int main()
{
Display *display;
int screennum;
int width;
int height;
Atom protocols;
int i;

const char *strdraw = “hello world”;

Window win;
GC gc;
XFontSet fontset;

// set the locale
const char *curlocale =setlocale(LC_ALL,”");
if( curlocale == NULL){
DUMP_ERR(”set locale fail\n”);
return 1;
}
DUMP_ERR(”locale is:%s\n”,curlocale);

if(!XSupportsLocale()){
DUMP_ERR(”X don’t support current locale\n”);
return 1;
}

// open display for X
display = XOpenDisplay(NULL);
if( !display ){
DUMP_ERR(”call XOpenDisplay(%s) fail\n”,XDisplayName(NULL));
return 1;
}

// get default screen
screennum = DefaultScreen(display);
width = DisplayWidth(display,screennum)/2;
height = DisplayHeight(display,screennum)/2;

// get the fontset
{
char **missing_charset_list_return;
int missing_charset_count_return;
char *def_string_return;
fontset = XCreateFontSet(display,”8x16,-*-gb2312.1980-0″,
&missing_charset_list_return,
&missing_charset_count_return,
&def_string_return);
if(missing_charset_count_return > 0){
for(i=0;i<missing_charset_count_return;i++){
DUMP_ERR(”fontset(%s) missing\n”,
missing_charset_list_return[i]);
}
DUMP_ERR(”def string(%s)\n”,def_string_return);
XFreeStringList(missing_charset_list_return);
XCloseDisplay(display);
return 1;
}
}

// create window
win = XCreateSimpleWindow(display,
RootWindow(display,screennum),
0,0,width,height,3,
BlackPixel(display,screennum),
WhitePixel(display,screennum));

protocols = XInternAtom(display, “WM_DELETE_WINDOW”, True);
XSetWMProtocols(display, win, &protocols, 1);

// select event
XSelectInput(display,win,
ExposureMask|KeyPressMask
|ButtonPressMask|StructureNotifyMask);

// create gc
{
unsigned long valuemask = 0;
XGCValues values;
gc = XCreateGC(display,win,valuemask,&values);
}

// show window
XMapWindow(display,win);

// event loop
while(1){
XEvent event;
XNextEvent(display,&event);

switch(event.type){
case Expose: // expose window
if( event.xexpose.count != 0) break;
draw(display,win,fontset,gc);
//XDrawString(display,win,gc,10,10,
//strdraw,strlen(strdraw));
break;

case ConfigureNotify: // when the window’s size change
width = event.xconfigure.width;
height = event.xconfigure.height;
break;
case ClientMessage :
if(event.xclient.data.l[0] == protocols){
DUMP_ERR(”recv destroy notify\n”);
XFreeFontSet(display,fontset);
XFreeGC(display,gc);
XDestroyWindow(display, win);
XCloseDisplay(display);
}
return 0;

default:
break;
}
}
}

static void draw(Display *display,Window win,XFontSet fontset,GC gc)
{
const char* pout = “Helo 你好 ,这是中文显示 i使用mb与wc两种输出”;
wchar_t wbuf[256];
int wlen = mbstowcs(wbuf,pout,strlen(pout));

XmbDrawString(display,win,fontset,gc,10,10,pout,strlen(pout));
XwcDrawString(display,win,fontset,gc,10,50,wbuf,wlen);
}
[/code:1]
回复

使用道具 举报

 楼主| 发表于 2005-3-16 22:17:04 | 显示全部楼层
Xwindows开发学习

补充
XIm开发

XIM(X输入模块)原理
XIM是为了使其它非英语国家在X中输入自己语言的办法 特别是对于双字节语言
XIM是使用一个输入服务器 为几个需要XIM输入的程序提供输入支持 每个程序申请一个XIC(X input context,x输入上下文)

XIM的开发与显示国际化一样
都需要locale被X支持

下面讲讲开发步骤
1 使用setlocale(LC_ALL,”")设置程序使用的locale为当前locale
2 使用XSupportsLocale检查是不是支持当前locale
3 使用XSetLocaleModifiers(”")从locale中读入@IM=…值 如果读入不成功那就不支持xim

4 开始X的正常编程 XOpenDisplay XCreateSimpleWindow XCreateGC 创建自己的窗口

5 使用XCreateFontSet选择程序使用的字体 注意需要的字体必须有 才能在程序中显示 (这点与xi18noutput一样)

6 调用XOpenIM连接xim服务器
7 使用XCreateIC创建输入上下文 创建时必须指定自己需要的风格 一共有四种风格 这里使用的是最简单的root风格
8 使用
XGetICValues(xic,XNFilterEvents,&im_event_mask,NULL);
XSelectInput(display,win,
ExposureMask| KeyPressMask
| StructureNotifyMask | im_event_mask);
来声明自己对XIM的事件也需要处理

9
XSetICFocus(xic); 把输入法窗口显示到最前
// show window
XMapWindow(display,win); 显示窗口

10 在事件循环中
XNextEvent(display,&event); //得到事件
if(XFilterEvent(&event,None)) continue; // 判断这个事件是不是xim会处理 如果xim没有处理 那返回false 程序处理这个事件

11 处理按键事件 使用 XwcLookupString查找刚才输入的内容
case KeyPress:
{
wchar_t buffer[1024];
Status status;
KeySym keysym;
int len = XwcLookupString(xic, &event, buffer, sizeof(buffer)/sizeof(wchar_t)-1,
&keysym, &status);
// use xwc should better,delete will be very easy
Bool redraw = False;

status指示当前状态 一共有四个
XLookupNone 没有状态
XLookupKeySym 查找按键输入状态
XLookupChars 查找字符状态
XLookupBoth 查找XLookupChars 和 XLookupKeySym
对这四个事件分别进行处理

具体看代码

xim就这样简单

下面是例子

#include <stdio.h>
#include <locale.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>

#define DUMP_ERR printf

static void draw(Display *display,Window win,XFontSet fontset,GC gc,const wchar_t*buf);

int main()
{
Display *display;
int screennum;
int width;
int height;
Atom protocols;
int i;

wchar_t strinput[1024]; // keep string in

Window win;
GC gc;
XIM xim;
XIC xic;
XFontSet fontset;

memset(strinput,0,sizeof(strinput));

// set the locale
const char *curlocale =setlocale(LC_ALL,"");
if( curlocale == NULL){
DUMP_ERR("set locale fail\n");
return 1;
}
DUMP_ERR("locale is:%s\n",curlocale);

if(!XSupportsLocale()){
DUMP_ERR("X don't support current locale\n");
return 1;
}

if(XSetLocaleModifiers("") == NULL)
DUMP_ERR("set locale modifiers fail,can't use XIM\n");

// open display for X
display = XOpenDisplay(NULL);
if( !display ){
DUMP_ERR("call XOpenDisplay(%s) fail\n",XDisplayName(NULL));
return 1;
}

// get the fontset
{
char **missing_charset_list_return;
int missing_charset_count_return;
char *def_string_return;
fontset = XCreateFontSet(display,"8x16,-*-gb2312.1980-0",
&missing_charset_list_return,
&missing_charset_count_return,
&def_string_return);
if(missing_charset_count_return > 0){
for(i=0;i<missing_charset_count_return;i++){
DUMP_ERR("fontset(%s) missing\n",
missing_charset_list_return);
}
DUMP_ERR("def string(%s)\n",def_string_return);
XFreeStringList(missing_charset_list_return);
}
}

// get default screen
screennum = DefaultScreen(display);
width = DisplayWidth(display,screennum)/2;
height = DisplayHeight(display,screennum)/2;

// create window
win = XCreateSimpleWindow(display,
RootWindow(display,screennum),
0,0,width,height,3,
BlackPixel(display,screennum),
WhitePixel(display,screennum));

protocols = XInternAtom(display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(display, win, &protocols, 1);
// create gc
{
unsigned long valuemask = 0;
XGCValues values;
gc = XCreateGC(display,win,valuemask,&values);
}

/** now will start open XIM **/
xim = XOpenIM(display,NULL,NULL,NULL);
if( !xim ){
DUMP_ERR("open XIM failed\n");
return 1;
}
// TODO select XIM mode

// create xic (input content)
{
XIMStyle style = XIMPreeditNothing|XIMStatusNone;
XVaNestedList list = XVaCreateNestedList(0,XNFontSet,fontset,NULL);
xic = XCreateIC(xim,XNInputStyle,style,
XNClientWindow,win,
XNPreeditAttributes,list,
XNStatusAttributes,list,
NULL);
XFree(list);
if( !xic ){
DUMP_ERR("open XIC failed\n");
return 1;
}
}

// select event
long im_event_mask;
XGetICValues(xic,XNFilterEvents,&im_event_mask,NULL);
XSelectInput(display,win,
ExposureMask| KeyPressMask
| StructureNotifyMask | im_event_mask);

XSetICFocus(xic);
// show window
XMapWindow(display,win);

Bool redraw = False;
// event loop
while(1){
XEvent event;
XNextEvent(display,&event);
if(XFilterEvent(&event,None)) continue;

switch(event.type){
case Expose: // expose window
if( event.xexpose.count != 0) break;
draw(display,win,fontset,gc,strinput);
//XDrawString(display,win,gc,10,10,
//strdraw,strlen(strdraw));
break;

case KeyPress:
{
wchar_t buffer[1024];
Status status;
KeySym keysym;
int len = XwcLookupString(xic, &event, buffer, sizeof(buffer)/sizeof(wchar_t)-1,
&keysym, &status);
// use xwc should better,delete will be very easy
Bool redraw = False;
switch(status){
case XLookupNone:
break;
case XLookupKeySym:
case XLookupBoth:
if(keysym == XK_Delete || keysym == XK_BackSpace ){
if(strinput[0]){
int size = wcslen(strinput);
strinput[size-1] = 0;
redraw = True;
}
break;
}
if( keysym == XK_Return ) break;
if( keysym == XLookupKeySym ) break;
case XLookupChars:
buffer[len] =0;
wcscat(strinput,buffer);
redraw = True;
break;
default:
break;

}
if(redraw)
draw(display,win,fontset,gc,strinput);
}
break;

case ConfigureNotify: // when the window's size change
width = event.xconfigure.width;
height = event.xconfigure.height;
break;
case ClientMessage :
if(event.xclient.data.l[0] == protocols){
DUMP_ERR("recv destroy notify\n");
XDestroyIC(xic);
XCloseIM(xim);
XFreeFontSet(display,fontset);
XFreeGC(display,gc);
XDestroyWindow(display, win);
XCloseDisplay(display);
}
return 0;

default:
break;
}
}
}

static void draw(Display *display,Window win,XFontSet fontset,GC gc,const wchar_t*strin)
{
//wchar_t wbuf[1024];
//int wlen = mbstowcs(wbuf,strin,strlen(strin));

XClearWindow(display, win);
//XmbDrawString(display,win,fontset,gc,10,10,strin,strlen(strin));
XwcDrawString(display,win,fontset,gc,10,50,strin,wcslen(strin));
}
回复

使用道具 举报

发表于 2005-3-16 22:19:15 | 显示全部楼层
支持一下。     
回复

使用道具 举报

 楼主| 发表于 2005-3-18 15:00:12 | 显示全部楼层
谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-6 11:41 , Processed in 0.042662 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表