|
|

楼主 |
发表于 2003-11-22 13:56:27
|
显示全部楼层
Opening And Closing The Connection To An X Server
打开和关闭连接到X服务器的连接
An X program first needs to open the connection to the X server. When we do that, we need to specify the address of the host running the X server, as well as the display number. The X window system can support several displays all connected to the same machine. However, usually there is only one such display, which is display number '0'. If we wanted to connect to the local display (i.e. the display of the machine on which our client program runs), we could specify the display as ":0". To connect to the first display of a machine whose address is "simey", we could use the address "simey:0". Here is how the connection is opened:
X程序首先需要打开连接到X服务器的连接。在我们完成这件工作的时候,我们需要指定运行X服务器的机器的地址,以及display号码。X window系统能够支持全部连接于同一个机器的好几个display。然而,通常只有一个这样的display,它的display号是‘0’。如果我们想要连接到本地display(也就是我们客户程序所运行的机器的display),我们可以指定display为’:0‘。要连接到地址为”simey“的机器的第一个display,我们能够使用地址”simey:0“。这儿是连接是如何被打开的:
#include <X11/Xlib.h> /* defines common Xlib functions and structs. */
.
.
/* this variable will contain the pointer to the Display structure */
/* returned when opening a connection. */
Display* display;
/* open the connection to the display "simey:0". */
display = XOpenDisplay("simey:0");
if (display == NULL) {
fprintf(stderr, "Cannot connect to X server %s\n", "simey:0");
exit (-1);
}
Note that is common for X programs to check if the environment variable 'DISPLAY' is defined, and if it is, use its contents as the parameter to the XOpenDisplay() function.
注意,对于X程序来说检查系统变量‘DISPLAY’是否被定义了是很常见的,而且如果是的话,使用它的内容作为XOpenDisplay()函数的参数。
When the program finished its business and needs to close the connection the X server, it does something like this:
当程序完成了它的使命并且需要关闭连接到X服务器的连接的时候,它如下动作:
XCloseDisplay(display);
This would cause all windows created by the program (if any are left) to be automatically closed by the server, and any resources stored on the server on behalf of the clients - to be freed. Note that this does not cause our client program to terminate - we could use the normal exit() function to do that.
这将导致所有由程序创造的窗口(如果还有剩下的话)自动被服务器关闭,而且为了客户的利益任何留在服务器上的资源-将被释放。注意这将不会导致我们的客户程序终止-我们使用普通的exit()函数来完成。
Checking Basic Information About A Display
检查关于Display的基本信息
Once we opened a connection to an X server, we should check some basic information about it: what screens it has, what is the size (width and height) of the screen, how many colors it supports (black and white? grey scale? 256 colors? more?), and so on. We will show a code snippet that makes few of these checks, with comments explaining each function as it is being used. We assume that 'display' is a pointer to a 'Display' structure, as returned by a previous call to XOpenDisplay().
一旦我们打开了一个连接到X服务器的连接,我们应当检查有关它的一些基本信息:他有什么样的屏幕,尺寸是多少(宽和高),它支持多少颜色(黑白?灰度?256色?更多?),以及等等。我们将展示一些作一些这样检查的代码片段,以及在使用中解释每个函数的注释。我们假定‘display’是一个指向‘Display’的结构的指针,由前面对XOpenDisplay()的调用返回的。
/* this variable will be used to store the "default" screen of the */
/* X server. usually an X server has only one screen, so we're only */
/* interested in that screen. */
int screen_num;
/* these variables will store the size of the screen, in pixels. */
int screen_width;
int screen_height;
/* this variable will be used to store the ID of the root window of our */
/* screen. Each screen always has a root window that covers the whole */
/* screen, and always exists. */
Window root_window;
/* these variables will be used to store the IDs of the black and white */
/* colors of the given screen. More on this will be explained later. */
unsigned long white_pixel;
unsigned long black_pixel;
/* check the number of the default screen for our X server. */
screen_num = DefaultScreen(display);
/* find the width of the default screen of our X server, in pixels. */
screen_width = DisplayWidth(display, screen_num);
/* find the height of the default screen of our X server, in pixels. */
screen_height = DisplayHeight(display, screen_num);
/* find the ID of the root window of the screen. */
root_window = RootWindow(display, screen_num);
/* find the value of a white pixel on this screen. */
white_pixel = WhitePixel(display, screen_num);
/* find the value of a black pixel on this screen. */
black_pixel = BlackPixel(display, screen_num);
There are various other macros to get more information about the screen, that you can find in any Xlib reference. There are also function equivalents for some of these macros (e.g. XWhitePixel, which does the same as WhitePixel).
有各种其他的宏来得到关于屏幕的更多信息,你可以从任何Xlib参考书中得到它们。还有和这些宏完成相同功能的函数(例如XWhitePixel,它和WhitePixel干一样的事情)。
Creating A Basic Window - Our "hello world" Program
创建一个简单窗口 - 我们的“hello world”程序
After we got some basic information about our screen, we can get to creating our first window. Xlib supplies several functions for creating new windows, one of which is XCreateSimpleWindow(). This function gets quite a few parameters determining the window's size, its position, and so on. Here is a complete list of these parameters:
在我们获得了一些有关我们的屏幕的基本信息之后,我们可以开始创建我们第一个窗口。Xlib提供数个函数来创建新窗口,其中的一个是XCreateSimpleWindow()。这个函数或者少量几个决定窗口的大小和位置等的参数。这有一个这些参数的完整列表:
Display* display
Pointer to the Display structure.
Window parent
The ID of an existing window that should be the parent of the new window.
int x
X Position of the top-left corner of the window (given as number of pixels from the left of the screen).
int y
Y Position of the top-left corner of the window (given as number of pixels from the top of the screen).
unsigned int width
Width of the new window, in pixels.
unsigned int height
Height of the new window, in pixels.
unsigned int border_width
Width of the window's border, in pixels.
unsigned long border
Color to be used to paint the window's border.
unsigned long background
Color to be used to paint the window's background.
Lets create a simple window, whose width is 1/3 of the screen's width, height is 1/3 of the screen's height, background color is white, border color is black, and border width is 2 pixels. The window will be placed at the top-left corner of the screen.
让我们创建一个简单窗口,它的宽是屏幕宽的1/3,高是屏幕高的1/3,背景色是白的,边框颜色是黑色的,而且边框宽2象素。窗口将会放置在屏幕的左上角。
/* this variable will store the ID of the newly created window. */
Window win;
/* these variables will store the window's width and height. */
int win_width;
int win_height;
/* these variables will store the window's location. */
int win_x;
int win_y;
/* calculate the window's width and height. */
win_width = DisplayWidth(display, screen_num) / 3;
win_height = DisplayHeight(display, screen_num) / 3;
/* position of the window is top-left corner - 0,0. */
win_x = win_y = 0;
/* create the window, as specified earlier. */
win = XCreateSimpleWindow(display,
RootWindow(display, screen_num),
win_x, win_y,
win_width, win_height,
win_border_width, BlackPixel(display, screen_num),
WhitePixel(display, screen_num));
The fact that we created the window does not mean it will be drawn on screen. By default, newly created windows are not mapped on the screen - they are invisible. In order to make our window visible, we use the XMapWindow() function, as follows:
我们创造了窗口的事实并不意味着它会被画在屏幕上。缺省的,新创建的窗口不会被映射于屏幕之上 - 它们是不可见的。为了使得我们的窗口可见,我们使用XMapWindow()函数,如下:
XMapWindow(win);
To see all the code we have gathered so far, take a look at the simple-window.c program. You'll see two more function not explained so far - XFlush() and XSync(). The XFlush() function flushes all pending requests to the X server - much like the fflush() function is used to flash standard output. The XSync() function also flushes all pending requests to the X server, and then waits until the X server finishes processing these requests. In a normal program this will not be necessary (you'll see why when we get to write a normal X program), but for now we put it there. Try compiling the program either with or without these function calls to see the difference in its behavior.
要看我们至今积累写出的所有代码,看看simple-window.c程序。你将看到至今没有解释的两个另外的函数 - XFlush()和XSync()函数用来清除仍未发送给X服务器的请求 - 很想用来清除标准输出的fflush()函数。XSync()函数也清除所有仍未发送给X服务器的消息,而且等待X服务器结束处理所有这些请求。在一个通常的程序中,这将不会是必要的(你可以看到为什么在我们开始写一个普通的X程序的时候),但对于现在我们把它放在那儿。尝试着有和去掉这些函数调用来编译程序,以观察它们行为上的不同点。
Drawing In A Window
在窗口中绘图
Drawing in a window can be done using various graphical functions - drawing pixels, lines, circles, rectangles, etc. In order to draw in a window, we first need to define various general drawing parameters - what line width to use, which color to draw with, etc. This is done using a graphical context (GC).
在窗口中绘图能够通过使用各种图形函数来完成 - 画点,线,圆,矩形,等。为了能够在窗口中绘图,我们首先需要定义几种通用的绘图参数 - 线宽使用多少的,绘图的颜色是什么,等。这个是用图形上下文(GC)来完成的。
Allocating A Graphics Context (GC)
分配图形上下文(GC)
As we said, a graphical context defines several attributes to be used with the various drawing functions. For this, we define a graphical context. We can use more than one graphical context with a single window, in order to draw in multiple styles (different colors, different line widths, etc.). Allocating a new GC is done using the XCreateGC() function, as follows (in this code fragment, we assume "display" is a pointer to a Display structure, and "win" is the ID of a previously created window):
如我所说,图形上下文给出几个用于绘图函数的属性。因此,我们定义一个图形上下文。我们能够在一个窗口中使用多余一个的图形上下文,以达到用多种风格(不同的颜色,线宽,等)绘图。分配一个新的GC是通过使用XCreateGC()函数来完成的,如下(在这个代码片段中,我们假定“display”是一个只想Display结构的指针,而起“win”是先前创建的窗口的ID):
/* this variable will contain the handle to the returned graphics context. */
GC gc;
/* these variables are used to specify various attributes for the GC. */
/* initial values for the GC. */
XGCValues values = CapButt | JoinBevel;
/* which values in 'values' to check when creating the GC. */
unsigned long valuemask = GCCapStyle | GCJoinStyle;
/* create a new graphical context. */
gc = XCreateGC(display, win, valuemask, &values);
if (gc < 0) {
fprintf(stderr, "XCreateGC: \n");
}
Note should be taken regarding the roles of "valuemask" and "values". Since a graphics context has zillions of attributes, and since often we don't want to define few of them, we need to be able to tell the XCreateGC() which attributes we want to set. This is what the "valuemask" variable is for. We then use the "values" variable to specify actual values for the attributes we defined in the "valuesmask". Thus, for each constant used in "values", we'll use the matching constant in "valuesmask". In this case, we defined a graphics context with two attributes:
注意“valuesmask”和“values”的角色。因为图形上下文有n多属性,并且我们不想定义它们中的一些,我们需要能够告诉XCreateGC()哪些属性是我们想要设置的。这就是“valuesmask”变量的用处。我们然后使用“values”变量来指定我们在“valuesmask”中定义的属性的值。因而,对于每个在“values”中使用的常量,我们将使用在“valuesmask”中相应的常量。在此例中,我们用两个属性定义图形上下文:
1. When drawing a multiple-part line, the lines should be joined in a 'Bevelian' style.
2. A line's end-point will be drawn straight (as opposed to ending the line in a round shape, if its width is more than 1 pixel wide).
1、当在画多部分的线的时候,线应该以‘Bevelian’风格连接起来。
2、线的终点将被直的画出来(与以圆角结束线相对,如果它的宽度大于一个象素)。
The rest of the attributes of this GC will be set to their default values.
这个GC的剩余属性将由它们的缺省值设定。
Once we created a graphics context, we can use it in drawing functions. We can also modify its parameters using various functions. Here are a few examples:
一旦我们创建了一个图形上下文,我们能够在绘图函数中使用它。我们还能够各种函数修改它的参数。这儿有几个例子:
/* change the foreground color of this GC to white. */
XSetForeground(display, gc, WhitePixel(display, screen_num));
/* change the background color of this GC to black. */
XSetBackground(display, gc, BlackPixel(display, screen_num));
/* change the fill style of this GC to 'solid'. */
XSetFillStyle(display, gc, FillSolid);
/* change the line drawing attributes of this GC to the given values. */
/* the parameters are: Display structure, GC, line width (in pixels), */
/* line drawing style, cap (line's end) drawing style, and lines */
/* join style. */
XSetLineAttributes(display, gc, 2, LineSolid, CapRound, JoinRound);
for complete information on the various attributes available in a graphics context, refer to the manual page of XCreateGC(). We will use just a few simple attributes in our tutorial, to avoid over-complicating it.
要获关于在图形上下文中有的各种属性的完整信息,参考XCreateGC()的手册页。我们将在我们的教程中仅仅使用几个简单的属性,以避搞得过度复杂了。
Drawing Primitives - Point, Line, Box, Circle...
基本绘图-点,线,框,圆...
After we have created a GC, we can draw on a window using this GC, with a set of Xlib functions, collectively called "drawing primitives". Without much fuss, lets see how they are used. We assume that "gc" is a previously initialized GC, and that 'win' contains the handle of a previously created window.
在我们创建了GC之后,我们能够使用这个GC在窗口上用一套Xlib函数绘画了,这些函数合成为“基本绘图函数”。废话不多说了,让我们看看它们是如何使用的吧。我们假定”gc“是先前初始化了的GC,而且‘win’包含了先前创建的窗口的句柄。
/* draw a pixel at position '5,60' (line 5, column 60) of the given window. */
XDrawPoint(display, win, gc, 5, 5);
/* draw a line between point '20,20' and point '40,100' of the window. */
XDrawLine(display, win, gc, 20, 20, 40, 100);
/* draw an arc whose center is at position 'x,y', its width (if it was a */
/* full ellipse) is 'w', and height is 'h'. Start the arc at angle 'angle1' */
/* (angle 0 is the hour '3' on a clock, and positive numbers go */
/* counter-clockwise. the angles are in units of 1/64 of a degree (so 360*64 */
/* is 360 degrees). */
int x = 30, y = 40;
int h = 15, w = 45;
int angle1 = 0, angle2 = 2.109;
XDrawArc(display, win, gc, x-(w/2), y-(h/2), w, h, angle1, angle2);
/* now use the XDrawArc() function to draw a circle whose diameter */
/* is 15 pixels, and whose center is at location '50,100'. */
XDrawArc(display, win, gc, 50-(15/2), 100-(15/2), 15, 15, 0, 360*64);
/* the XDrawLines() function draws a set of consecutive lines, whose */
/* edges are given in an array of XPoint structures. */
/* The following block will draw a triangle. We use a block here, since */
/* the C language allows defining new variables only in the beginning of */
/* a block. */
{
/* this array contains the pixels to be used as the line's end-points. */
XPoint points[] = {
{0, 0},
{15, 15},
{0, 15},
{0, 0}
};
/* and this is the number of pixels in the array. The number of drawn */
/* lines will be 'npoints - 1'. */
int npoints = sizeof(points)/sizeof(XPoint);
/* draw a small triangle at the top-left corner of the window. */
/* the triangle is made of a set of consecutive lines, whose */
/* end-point pixels are specified in the 'points' array. */
XDrawLines(display, win, gc, points, npoints, CoordModeOrigin);
}
/* draw a rectangle whose top-left corner is at '120,150', its width is */
/* 50 pixels, and height is 60 pixels. */
XDrawRectangle(display, win, gc, 120, 150, 50, 60);
/* draw a filled rectangle of the same size as above, to the left of the */
/* previous rectangle. note that this rectangle is one pixel smaller than */
/* the previous line, since 'XFillRectangle()' assumes it is filling up */
/* an already drawn rectangle. This may be used to draw a rectangle using */
/* one color, and later to fill it using another color. */
XFillRectangle(display, win, gc, 60, 150, 50, 60);
Hopefully, you got the point by now. We will mention a few more functions that may be used in a similar fashion. For example, XFillArc() takes the same parameters as XDrawArc(), but draws only the inside of this arc (like XFillRectangle() does to a rectangle drawn using the XDrawRectangle() function). There is also an XFillPolygon() function that fills the inside of a polygon. It takes almost the same parameters as XDrawLines(). However, if the last point in the array has a different location than the first point in the array, the XFillPolygon() function automatically adds another "virtual" lines, connecting these two points. Another difference between the two functions, is that XFillPolygon() takes an additional parameters, shape, that is used to help the X server optimize its operation. You can read about it in your manual pages. There are also plural versions for these functions, namely XFillArcs() and XFillRectangles().
但愿你跟上了我的进度。我们还将提到更多的一些使用上差不多的函数。例如,XFillArc()和XDrawArc()带有相同的参数,但是只画出弧的内部(像XFillRectangle()函数所作的和用XDrawRectangle()函数画出的矩形一样)。还有一个填充多边形内部的XFillPolygon()函数。它和XDrawLines()基本上有相同的参数。然而,如果数组的最后一个点和第一个点处于不同的位置,XFillPolygon()函数自动添加一条”virtual“线,连接这两个点。两个函数的另外一个不同点就是XFillPolygon()带另外一个参数,shape。它用来帮助X服务器优化它的行为。你能够在手册页上学到这些。对于这些函数还有复数版本,名字为XFillArcs()和XFillRectangles()。
The source code for a program doing these drawings is found in the file simple-drawing.c.
完成这些绘画的程序的源代码位于文件simple-drawing.c中。 |
|