introduction
This tutorial is the first part of the "Would-BE" series tutorial for the X-window programming. In order to unilateral, this tutorial is useless because a real X window programmer usually uses a higher abstract level, such as MODIF (or its free version of Lestiff), GTK, QT or other similar libraries. . But ... maybe we should start from a place that is easier to learn. Because, I know how they work should never be a bad idea.
After reading this tutorial, the reader should be able to write a very simple X-window graphics, but there is no specific application written in such a way, for those situations, the abstract level mentioned above is higher Library.
X Window System Customer / Server Mode
The main purpose of the development X window system was only one, that is, flexibility. This flexibility means that although something seems to work, but actually works in a very far. Therefore, the lower level implementation must provide a tool for drawing a plot window, processing user input, painting, using color, etc. Under this request, it is determined that the system is divided into two parts, the client, and the server side. The client decides what to do, the server performs the real drawing and accepts the user's input and send it to the client.
This mode is just the opposite of the concept of clients and server-side clients us generally habit. In our case, the user is sitting before the server controlled the machine, but the client is running on the remote host. The server-side controls the display, mouse, and keyboard. A client may be connected to the server side, requiring it to draw a window (or a bunch), and require the server to pass the user to its window. As a result, several clients may connect to a server-side - some are running an email software, some are running a web browser. When the user enters the command to the window, the server side will packet the command to the client to control the client that the window, the client determines what is done according to the event, and send the request to let the server.
The session described above is transmitted by X message protocol. This protocol is implemented on the TCP / IP protocol, which allows clients in this network to access any server side in a network. Finally, the X server side can run on the same machine with the client to obtain performance optimization (note that an X protocol event may reach hundred KB), such as using shared memory, or using UNIX Domain Socket (in a UNIX system A method of creating a local channel between two processes).
Graphical User Interface (GUI) Programming - Asynchronous Programming Mode
Unlike our usual pleasure, a GUI program usually uses asynchronous programming mode, which is "event-driven programming" to be introduced below. This "event-driven programming" means that the program is usually in idle state, waiting for an event from the X server, etc., etc., it is necessary to make a corresponding thing according to the event. An event may be "the user is somewhere in the screen x, y click the left mouse button", or "the window you control needs to be heavy." Because the program responds to the user's request, it also needs to refresh your own request queue, so you need to use a shorter event to process an event (for example, as a recognized criterion, no more than 200 milliseconds).
This also implies an event that requires a program to process a long time (such as a network connection to the remote server, or connecting a database, or unfortunate to process a large file replication). This requires the program to use asynchronous ways to handle instead of usual synchronization. At this time, there should be a variety of asynchronous programming methods to perform these time-consuming work, or simply handle them to a thread or process.
According to the above description, a GUI program should work like the following ways: performing an initialization work connection X server for looping with X-related initialization work
Accepting the next event from the X server Send a variety of drawing instructions to the X server if the event is an exit event, end the loop closing the connection to the X server for resource release work
The basic idea of XLIB
The X protocol is very complicated. For everyone, it is a library called "XLIB" for everyone to waste time. This library provides a very bottom-up means of accessing any X servers. Because the X protocol has been standardized, theoretically, the client can access any X servers using any XLIB implementation. Today, this can look very trivial, but if returned to the era of using character terminals and proprietary drawing methods, this should be a big breakthrough. In fact, you quickly discovered how exciting things around the thin clients, window terminal servers.
X display
Basic thinking using XLIB is x display. It represents a structure that opens to the X server. It hides a queue saved from the Event from the X server, and a request queue that saves the client to send to the server. In XLIB, this structure is named Show "Display". When we open a connection to the X server, the library returns a pointer to this structure. Then we can use this pointer to use a variety of functions in XLIB.
GC - graphic context
When we conduct a variety of drawing operations (graphics, text, etc.), we may use many parameters to specify how to draw, prospect, background, what color use, what fonts, etc., and so on. In order to avoid setting an amazing parameters for each drawing function, we use a graphical context structure called "GC". We set various drawing parameters in this structure, and then pass it to the drawing function. This should be a very convenient way, especially when we use the same parameters in a series of operations.
Object handle
When the X server creates a wide variety of objects, such as windows, drawings, and cursors - the corresponding function returns a handle. This is an identity of an object present in the X server space - instead of in our application space. Later we can use the XLIB's function to manipulate these objects through the handle. The X server maintains an actual object to the mapping table of the handle. XLIB provides various types to define these objects. Although these types are actually just simple integers, we should continue to use these types of names - the reason is to port.
XLIB structure memory allocation
The interface of XLIB uses various types of structures. Some can be allocated by the user directly, some can only be assigned by a special XLIB library function. In the case where the library is used, the library generates the structure of the appropriate initial parameter. This is very convenient for everyone, specifying the initial value is very headache for less skilled programmers. Remember -XLIB wants to provide very flexible features, which means it will become very complicated. The feature that provides initial value settings will help those programmers who have just started using X, and will not interfere with those high masters.
When release memory, we use the same way to the application (for example, using free () to release the memory of malloc () applications). So, we must use XFree () to release memory.
event
A structure called "Xevent" to save events accepted from the X server. XLIB provides a very large amount of event type. Xevent includes the type of events and data related to events (such as events generated on the screen, the events, etc. of the mouse button), and therefore, to read the data in the appropriate events based on the event type. At this time, the Xevent structure uses the union of the C language to save possible data (if you don't know what C, what is going on, then you have to take some time to read your textbooks). As a result, we may be subject to Xexpose events, an Xbutton event, an XMotion event, and more. Compile XLIB-based procedures
Compiling XLIB-based programs need to be connected to the XLIB library. You can use the following command line:
CC Prog.c -o prog -lx11
If the compiler is not found to find the X11 library, you can try to add "-l" logo, like this:
CC Prog.c -o PROG -L / USR / X11 / LIB -LX11
Or this (for version 6 using X11)
CC Prog.c -o PROG -L / USR / X11R6 / LiB -LX11
On the Sunos 4 system, the library of x is putted / usr / openwin / lib
CC Prog.c -o prog -l / usr / openwin / lib -lx11
Wait, specific analysis
Open, close to a X server connection
A X program first opens to the X server connection. We need to specify the address of the host running the X server, and the display number. The X window allows a machine to open multiple displays. However, there is usually only one displayed "0" display. If we want to connect to the local display (for example, the machine is displayed at the same time, we can connect directly to ": 0" directly. Now let's exemplish the display of "SIMEY" machine, we can use the address "SIMEY: 0", how to connect below
#include
.
.
/ * 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 the X program is usually checked whether the environment variable "Display" is defined. If defined, it can be used directly as the connection parameters of the XOpendisplay () function.
When the program completes its work and needs to be closed to the X server, it can do this:
XCloseDisplay (Display) and DISPLAY
This will cause the X server to close all the windows you created for us and any resource applied by the X server is released. Of course, this does not mean the end of our client program.
Check the relevant basic information displayed
Once we open a connection to the X server, we should check some basic information related to it: What kind of screen is there, the screen size (long and width), how many colors (black and white? Gray level ? 256 colors? Or more), and so on. We will demonstrate some relevant operations. We assume that the variable "Display" points to a display structure obtained by calling 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;
/ * The Size of the Screen, in Pixels. * /
INT screen_width;
int Screen_Height;
/ * this variable will be used to store theid of the root window of oes /
/ * Screen. Each Screen Always Has A Root Window That Covers The Whole * /
/ * Screen, And always exissrs. * /
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 latter. * /
Unsigned long white_pixel;
UNSIGNED Long Black_pixel;
/ * Check the Number of the default screen for ur x server. * /
Screen_num = defaultscreen (display); 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 still many other macros to help us get the information displayed, you can find it in the reference in XLIB. There are still many equivalent functions that can be completed. Create a basic window - our "Hello World" program
After we get the basic information of some windows, we can start creating our first window. XLIB supports several functions to create a window, one of them is XcreateSimpleWindow (). This function uses few parameters to specify the size, location, etc. of the window. The following is a list of complete parameters:
Display * DISPLAY
Pointer to display structure
Window Parent
The ID of the parent window of the new window.
Int x
The upper left X coordinate of the window (unit is a screen pixel)
Int Y
The upper left y coordinate of the window (unit is a screen pixel)
Unsigned int width
Width of the window (unit is a screen pixel)
Unsigned int Height
The height of the window (unit is a screen pixel)
Unsigned int border_width
Window border width (unit as screen pixel)
Unsigned long border
Color used to draw window borders
Unsigned long background
Color used to draw windows background
Let's create a simple window, its width is 1/3 of the screen width, the height is 1/3 of the screen, the background color is white, the border is black, the width of the border is 2 pixels. This window will be placed onto the top left corner of the screen.
/ * 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;
/ * Sests 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);
In fact, we create a window does not mean that it will be immediately displayed on the screen. By default, the new window will not be mapped to the screen - they are invisible. In order to let us create a window can be displayed on the screen, we use the function xmapWindow ():
XMapWindow (WIN);
If you want to see the code we have lifted so far, please visit the source Simple-Window.c. You will find two new functions - xflush () and xsync (). Function XFlush () Refresh All requests to X Server in Waiting Status - Very like FFLUSH () refreshes all content to standard output. XSync () also refreshes all requests in the waiting state, and then wait for the X server to process all the requests to continue. In a general program, this is not necessary (accordingly you can find us just write a general program), but we now put them now, try different behaviors in the case of or without these functions. Draw in the window
Drawing in the window You can use a variety of drawing functions - draw points, lines, circles, rectangles, and more. In order to draw in one window, we first need to define various parameters - such as the width of the line, what color is used, and so on. This requires a graphic context (GC).
Apply for a graphical context (GC)
As we have mentioned, a graphical context defines some parameters to use the drawing function. Therefore, in order to draw different styles, we can use multiple graphics contexts in one window. Using function XcreateGc () can apply to a new graphical context, as described in this code (in this code, we assume "Display" point to a display structure, "win" is the ID of the currently created window):
/ * this variable will contain the handle to the return 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 create 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 that the role of the variable "Valuemask" and "VALUES" should be considered. Because a graphic context has a quantitative property, and usually we only need to set a part of it, what property we need to tell XCReateGc () is what we need to set, this is the function of variable "valuemask". Let's then specify the real value by "VALUES". In this example, we define two attributes in the graphical context:
1 When drawing a multiple part of the line, the line uses "bevelian" style when connecting
2 One line of terminal is drawn straight instead of circular
Other unspecified attribute GC will use the default.
Once we created a graphical context, we can use it in a variety of drawing functions, we can also change its properties in order to adapt to other functions.
/ * 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;
If you want to know the properties setting method of all graphics context, refer to the user documentation of the function XcreateGc (). We are here to avoid too complicated only a small part of the very simple properties.
Drawing basic elements - point, line, rectangular, round ...
After we created a GC, we can use a series of XLIB functions through the GC in a window, the collection of this function is called "basic elements of the drawing". For the sake of easy, let us take an example to see how they work. Here we assume that "GC" is a previously created GC, "WIN" is a handle that has created a good window.
/ * 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 points '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 elipse) 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 AGLE1 = 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 connection, whose * /
/ * Edges Are Given in an Array of XPoint Structure. * /
/ * The Following Block Will Draw A Triangle. We Use a block, since * /
/ * The c language allows defining new variables onfining new variables only in the basenning 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 (point) / sizeof (XPoint);
/ * Draw A Small Triangle at The Top-Left Corner of The Window. * /
/ * The Triangle IS Made of a set of conspecutive lines, whose * /
/ * end-point pixels area 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 flilling up * // * an already DRAWN Rectangle. this May be used to draw a rectangle use * /
/ * One Color, And Later To Fill It Using Another Color. * /
XfillRectangle (Display, WIN, GC, 60, 150, 50, 60);
If you feel that you have seized the key points of using these functions, then our instructions will become simple. We will mention other functions that use the same method. For example, Xfillarc () uses the same parameters as XDrawarc (), but it is only drawing a circle (similar, XfillRectangle () is only drawn inside the rectangular area). There is also a function XFillPolygon () responsible for populating a polygonal area. It is similar to xDrawlines (). However, it is important to note that if the point provided in the last parameter in the matrix is not in the same location, the function XFillPolygon () adds a virtual line to connect to the two points. Another difference between the two functions is that XfillPolygon () uses an additional parameter, shape, this parameter can help the X server to optimize its drawing work. You can find detailed content in the manual. The above functions also exist their plural drawings, named xfillarcs () and XFillRectangles ().
Please refer to the program simple-drawing.c above
X event
In an XLIB program, all thections are driven by events. The reaction for event "expose" is what is drawn on the screen. If part of the program window is covered, then it is revealed (for example, a window covers another window), the X server will send a "expose" event to let the program know part of its window should be resembled. The user's input (press keyboard, mouse movement, etc.) is also made into a series of events.
Use event mask to register event type
A program is created after creating a window (or a few), it should tell X servers to see which events are to accept it. By default, no event will be sent. The program can register a lot of mouse events (you can also call "pointers"), keyboard events, exposure events, and more. This is entirely intended to optimize the server - the client's communication (for example, there is no reason to send it to the other end of the Earth is not interested).
In XLIB, we use functions XselectInput () to register the events you are acceptable. This function accepts 3 parameters - display structure, a window ID, and a mask that it wants to accepted. Parameter Window ID allows us to register different types of events for different window. The following example shows our "Expose" event for the window ID "WIN":
XselectInput (Display, Win, Exposuremask;
ExpositionMask is defined in the header file "x.h" if we want to register more event types, we can use the logical "OR", as follows:
XselectInput (Display, Win, Exposuremask | ButtonPressmask;
This will register the event "Expose" and registered a mouse button event. You should notice that a mask can describe a variety of event types.
Note: A frequent program bug is a code that adds a new type of event to the program, but does not remember the type of event added in the function XselectInput (). At this time, the programmer may be distressed, sitting in front of the computer to debug his procedure, "Why don't my program not pay attention to me, I have released the button?", Finally I found it only registered. The event pressed by the button is not registered.
Receive event - write event loops
After registering the type of events of interest, we should enter the event loop and process them. There are many ways to achieve event cycles, but it is more general and simple as follows:
/ * This Structure will Contain The Event's data, overce received. * /
XEVENT AN_EVENT;
/ * ENTER AN "endless" loop of handling events. * /
While (1) {
XNEXTEVENT (Display, & AN_EVENT);
Switch (AN_EVENT.TYPE) {
CASE EXPOSE:
/ * Handle this Event Type ... * /
.
.
Break;
Default: / * Unknown Event Type - Ignore It. * /
Break;
}
}
Functions XNEXTEVENT get a new event from the X server. If not, it will be blocked until an event is accepted. After the function returns, the data of the event will be placed in the parameter of the second type Xevent. The "Type" domain of the event variable before, indicating the type of the event. EXPOSE is a type of event that tells us that the window needs to be heavy. After processing this incident, we return to get the next event to be processed. Obviously, we should provide some way to end the program. Generally send a "quit" incident.
Expose event
Exposure events are one of the most frequently received events. It will appear in the following cases:
A window covering our window is removed, and our window is re-exposed. Our windows are opened by other windows. Our window is first mapped to the screen. Our windows are restored from the minimization to the open state.
You should have noticed that there is a hidden hypothesis - the content covered when the window is covered. You may ask questions why the X server does not save those content. The answer has only one - save memory. At a moment, there may be a large number of windows on the screen, saving their content will require a very large amount of memory (for example, a Bitmap image of a 256-color resolution is 400 * 400 requires at least 160KB memory to save it. Now consider having 20 windows, some of this may have a larger size). In fact, there is a way to tell the X server to save the window in special circumstances, we will introduce later.
When we get a "expose" event, we should get event data from the Xevent structure "Xexpose" member (in our routines, it is "an_event.xexpose"). In addition, that structure also includes some interesting domains:
count
How much exposed events in the event queue of the server. This is very useful when we have gained multiple exposure events - we usually avoid performing heavy paintings until it is determined that it is the last exposed event (so until it is 0).
Window window
The ID of the window that sends the redraminated event (our program is registered with the event for multiple windows).
INT X, Y
From the top left of the window, the left coordinate of the area of the heavy draw is required.
Int Width, Height
It is necessary to be high in the region of the heavy.
In our demonstration, we ignored the area that needs to be returned, but he retrays throughout the window, which is very inefficient, we will demonstrate some technologies that only heavy pictures of the region that needs to be heavy. . The following is an example, how to draw a straight line in one window when we receive any "expose" event. This is the code of the CASE segment of the event cycle:
CASE EXPOSE:
/ * if we have several Other Expose Events Waiting, Don't RedRaw. * /
/ * WE WILL DO The Redrawing WHEN We Receive The last of them. * /
IF (AN_EVENT.XEXPOSE.COUNT> 0)
Break;
/ * OK, now Draw the line ... * /
XDrawline (Display, WIN, GC, 0, 100, 400, 100);
Break;
Get user input
For now, the user's input is mainly from two places - mouse and keyboard. There are all kinds of events to help us get the user's input - the key on a keyboard is pressed, the key on a keyboard is released, the mouse cursor leaves our window, the mouse cursor enters our window. and many more.
Mouse button event and loosening event
The first event we handed for our window is the mouse button time. In order to register a such event type, we will add the following masks.
ButtonPressmask
Notify us of any mouse button in the window to press the action
ButtonReleaseMask
Notify us of any mouse button in the window to loosen the action
Check the following event types through Switch in our event cycle.
Buttonpress
A mouse button on our window is pressed
ButtonRelease
A mouse button on our window is released
In the event structure, get the type of event through "an_event.xbutton", and it also includes the following interests:
Window window
The ID of the target window sent by the event (if we register an event for multiple windows)
INT X, Y
From the upper left coordinate of the window, the mouse button presses the coordinates of the time in the window.
Int Button
The button of the label on the mouse is pressed, the value may be button1, button2, button3
Time Time
The event is placed in the queue. Can be used to achieve double-click processing
The following example will demonstrate how we draw a picture at the position of the mouse, no matter when we receive the "mouse button" of the "Mouse", we draw a black point, receive the number 2 button "" When the mouse is pressed, we wipe off that black point (for example, draw a white point). We assume that there are two GCs now, GC_DRAW uses the following code
Case ButtonPress:
/ * Store The Mouse Button Coordinates in 'Int' Variables. * /
/ * Also store the id of the window on which the mouse was * /
/ * PRESSED. * /
X = an_Event.xButton.x;
Y = an_Event.xbutton.y;
THE_WIN = an_Event.xbutton.window;
/ * Check Which Mouse Button Was Pressed, And Act Accordingly. * /
Switch (an_event.xbutton.button) {
Case Button1: / * Draw a Pixel at the mouse position. * /
XDrawPoint (Display, THE_WIN, GC_DRAW, X, Y);
Break;
Case Button2:
/ * ERASE a Pixel at the mouse position. * /
XDrawPoint (Display, THE_WIN, GC_ERASE, X, Y);
Break;
Default: / * probably 3rd Button - Just Ignore this event. * /
Break;
}
Break;
Entering and leaving the mouse cursor
Another program usually interested in the event that the mouse cursor enters a window of a window and an event of the field of the window. Some programs use this event to tell the user program now in the focus. In order to register such an event, we will register several masks in the function XselectInput ().
EnterwindowMask
Notify us of the mouse cursor to enter any of our windows
LeaveWindowMask
Notify us of the mouse cursor to leave any of our windows
The branch check in our event loop will check the following event types
EnterNotify
The mouse cursor entered our window
LeaveNotify
The mouse cursor left our window
The data structure of these event types is accessed, for example, "an_Event.xcross", which also contains the following interesting member variables:
Window window
The ID of the target window sent by the event (if we register an event for multiple windows)
Window Subwindow
In an entry incident, it means from that sub-window to our window, in an left incident, it means to enter the child window, if it is "none", it means to enter us from outside Window.
INT X, Y
From the left coordinate of the window, the coordinates of the mouse cursor in the window when the event is generated.
Int Mode
The button of the label on the mouse is pressed, the value may be button1, button2, button3
Time Time
The event is placed in the queue. Can be used to achieve double-click processing
Unsigned int State
This event occurs when the mouse button (or keyboard key) is pressed - if any. This member uses a bitwise or manner
Button1mask
Button2mask
Button3mask
Button4mask
Shiftmask
LOCKMASK
Controlmask
MOD1MASK
MOD2MASK
MOD3MASK
MOD4MASK
Their names can be extended. When the fifth mouse button is pressed, the remaining attributes indicate other special keys (such as MOD1 generally "alt" or "meta" keys)
Bool Focus
When the value is TRUE, the window has obtained the keyboard focus, FALSE is reversed.
Keyboard focus
There will be a lot of windows at the same time on the screen, but only one window can get the use of the keyboard at the same time. How is the X server know which window can send a keyboard event? This is achieved by using the keyboard focus. Only one window can get keyboard focus at the same time. The existence of a function in the XLIB function allows the program to get the specified window to get the keyboard focus. Users typically use the window manager to set the focus for the window (usually the title bar of the window). Once our window gets the keyboard focus, press and release each key will cause the server to send an event to our program (if you have registered the type of these events).
Keyboard key Press and release the event If the window controlled window gets the keyboard focus, it accepts the press and release events of the button. In order to register the type of these events, we need to register the following masks through a function xselectInput (). KeyPressmask
Notify us of the program when the button is pressed
KeyPressmask
Notify us of the program when the button is released
The branch check in our event loop will check the following event types
Window window
The ID of the target window sent by the event (if we register an event for multiple windows)
Unsigned int keycode
The encoding of the key being pressed (or loosen). This is some x internal encoding, which should be translated into a keyboard key symbol to be convenient, will be described below.
INT X, Y
From the left coordinate of the window, the coordinates of the mouse cursor in the window when the event is generated.
Time Time
The event is placed in the queue. Can be used to achieve double-click processing
Unsigned int State
This event occurs when the mouse button (or keyboard key) is pressed - if any. This member uses a bitwise or manner
Button1mask
Button2mask
Button3mask
Button4mask
Shiftmask
LOCKMASK
Controlmask
MOD1MASK
MOD2MASK
MOD3MASK
MOD4MASK
Their names can be extended. When the fifth mouse button is pressed, the remaining attributes indicate other special keys (such as MOD1 generally "alt" or "meta" keys)
As we mentioned earlier, the button coding does not make sense to us, which is hardware class encoding generated by the keyboard connected to the X server and is related to a keyboard with a model. In order to explain which button generated by the end, we translate it into the key symbol that has been standardized. We can use the function xkeycodetoKeysym () to complete this translation. This function uses 3 parameters: a displayed pointer, the keyboard encoding to be translated, and an index (we use "0" here). The standard XLIB key code can be referred to the file "X11 / Keysymdef.h". In the following example we use the function xkeycodetokeysym to handle the button operation, we tell how to handle the button event in the following order: Press the "1" button to draw a point in the current location of the mouse. Press the "DEL" button to erase the point. Press any alphanumeric key (A to Z, uppercase or lowercase), will be printed in the standard output. Other buttons will be ignored. Assuming the "Case" segment code below is in a message loop.
Case KeyPress:
/ * Store The Mouse Button Coordinates in 'Int' Variables. * /
/ * Also store the id of the window on which the mouse was * /
/ * PRESSED. * /
x = an_ever.xKey.x;
y = an_Event.xKey.y;
THE_WIN = an_Event.xkey.window;
{
/ * Translate the key code to a key symbol. * /
Keysym key_symbol = xkeycodetokeysym (display, an_event.xkey.keycode, 0);
Switch (Key_Symbol) {
Case XK_1:
Case XK_KP_1: / * '1' Key Was Pressed, Either The Normal '1', or * // * The '1' on the keypad. Draw the current pixel. * /
XDrawPoint (Display, THE_WIN, GC_DRAW, X, Y);
Break;
Case XK_Delete: / * del key was press, ERASE The Current Pixel. * /
XDrawPoint (Display, THE_WIN, GC_ERASE, X, Y);
Break;
Default: / * Anything else - Check if it is a letter key * /
IF (key_symbol> = xk_a && key_symbol <= xk_z) {
INT ASCII_KEY = Key_SYMBOL - XK_A 'A';
Printf ("Key Pressed - '% C' / N", ASCII_Key);
}
IF (key_symbol> = xk_a && key_symbol <= xk_z) {
INT ASCII_KEY = Key_SYMBOL - XK_A 'A';
Printf ("Key Pressed - '% C' / N", ASCII_Key);
}
Break;
}
}
Break;
You will find the way the keyboard key symbol to the transformation of the physical key code, the program should be careful to handle various possible situations. At the same time, we assume that the symbol value of the letter key is continuous.
X Event - a complete example
We will give an example Events.c for a complete handling event. Create a window to the program, do some painting work above, then enter an event loop. If it gets an exposed event - it sagizes the entire window. If it gets a mouse left mouse button, it draws a black point in the mouse cursor. If the mid button of the mouse is pressed, it draws a white point at the mouse cursor (for example, picking out that point). It should be noted that this graphic is how the change is processed. It is not very effective for drawing the proper color. We need to record the changes in color so that we can draw them with the correct color when the next exposure event is coming. We use a huge matrix of (1000 * 1000) to save pixels. At first, all units are set to 0. When drawing a point, we set this unit 1. If the point is drawn on white, we set this unit into -1. We can't just put the black into 0, otherwise we will start the painting will be accidentally deleted. Finally, the user presses any button on the keyboard and the program will exit.
When running this program, you may notice that the movement event will often drain it. If the mouse moves very quickly, we will not receive all events. As a result, if we want to handle this situation, we need to remember the last mouse position when you receive an event, and then draw a line between two points. The general drawing program is doing this.
Font structure
In order to support flexible fonts, a font structure is defined, and the type XFontStruct is defined. This structure is used to include information of a font, which is used to help some of the function processing font selection and text drawing.
Load a font
As a first step in drawing text, we use font load functions, such as XLoadQueryFont (). This function requires the X server to load fonts of a given name. If the font is discovered, the server loads the font and returns a pointer to the XFontStruct structure. If the font is not discovered, or the load failed, a value NULL is returned. There may be two names per font. One is a long string, indicating all the properties of the font (font, font size, slope / black body / black body, etc.). The other is a short alias, configured for their respective servers. As an example, we try to load "* -helvetica - * - 12- *" font: / * This Pointer Will Hold The Returned Font Structure. * /
XFontStruct * font_info;
/ * Try to load the given font. * /
Char * font_name = "* -helvetica - * - 12- *";
Font_info = xloadQueryFont (Display, Fond_Name);
IF (! font_info) {
FPRINTF (stderr, "xload uerfont: failed loading font '% s' / n", font_name);
}
Give a graphical context allocated font
After we load the font, we need to assign it to a GC. Suppose a GC called "GC" already exists, below is how we do:
XSETFONT (Display, GC, Font_INFO-> FID);
The "FID" area is a XFontStruct structure to identify various loaded fonts for various requests.
Drawing text in a window
Once we load fonts for our GC, we can use, for example, functions xDrawstring (), draw text in our window. This function can draw text in a given location in the window. The given position will be counted from the bottom left of the drawn text, the following is an example:
/ * Assume That Win_Width Contains the width of ot window, win_HEight * /
/ * Contains the Height of Our window, and 'win' is the the handle of ot window. * /
/ * Some Temporary Variables use for the drashing. * /
INT X, Y;
/ * Draw A "Hello World" string on the top-left side of our window. * /
X = 0;
y = 0;
XDrawString (Display, WIN, GC, X, Y, "Hello World", Strlen ("Hello World");
/ * Draw A "Middle of the road" string in the middle of ot window. * /
Char * text_string = "middle of the road";
/ * Find the width, in pixels, of the text this will be drawn using * /
/ * The given font. * /
Int string_width = xtextwidth (font_info, text_string, strlen (text_string)); / * Find The Height of the Characters Drawn Using this font. * /
INT fond_height = font_info-> ascent font_info-> descent;
X = (win_width - string_width) / 2;
Y = (win_width - font_height) / 2;
XDrawString (Display, WIN, GC, X, Y, "Hello World", Strlen ("Hello World");
The following description should be more clearly available:
The function xtextwidth () is used to predict the length of the string, when it uses the specified font to draw. It is used to check that the beginning there is the end of the two names "ascent" and "descent" attributes that appear to be "ascent" and "descent" at the beginning of the center of the center of the window. Basically, the characters of a font are painted on a horizontal line of an illusion. Some characters are drawn on the horizontal line, some painted below. The highest character is drawn on the "font_info-> ascent" line, the lowest portion is below the "Font_Info-> Descent" line. Therefore, these two deserves and indicate the height of the font.
The above source program can be referenced to the file Simple-text.c