Hands-on Projects for the Linux Graphics Subsystem
|
As we see in section 1.2 XOpenDisplay() is the routine called by the X Client to make the connection with the X Server. XOpenDisplay() returns a pointer to the Display struct. Display becomes after the connection the interface from the X Client to the X Server.
As we previously saw in section 1.2 Display is of type _XDisplay, which is defined in Xlibint.h as:
struct _XDisplay { XExtData *ext_data; /* hook for extension to hang data */ struct _XFreeFuncs *free_funcs; /* internal free functions */ int fd; /* Network socket. */ int conn_checker; /* ugly thing used by _XEventsQueued */ int proto_major_version;/* maj. version of server's X protocol */ int proto_minor_version;/* minor version of server's X protocol */ char *vendor; /* vendor of the server hardware */ XID resource_base; /* resource ID base */ XID resource_mask; /* resource ID mask bits */ XID resource_id; /* allocator current ID */ int resource_shift; /* allocator shift to correct bits */ XID (*resource_alloc)( /* allocator function */ struct _XDisplay* ); int byte_order; /* screen byte order, LSBFirst, MSBFirst */ int bitmap_unit; /* padding and data requirements */ int bitmap_pad; /* padding requirements on bitmaps */ int bitmap_bit_order; /* LeastSignificant or MostSignificant */ int nformats; /* number of pixmap formats in list */ ScreenFormat *pixmap_format; /* pixmap format list */ int vnumber; /* Xlib's X protocol version number. */ int release; /* release of the server */ struct _XSQEvent *head, *tail; /* Input event queue. */ int qlen; /* Length of input event queue */ unsigned long last_request_read; /* seq number of last event read */ unsigned long request; /* sequence number of last request. */ char *last_req; /* beginning of last request, or dummy */ char *buffer; /* Output buffer starting address. */ char *bufptr; /* Output buffer index pointer. */ char *bufmax; /* Output buffer maximum+1 address. */ unsigned max_request_size; /* maximum number 32 bit words in request*/ struct _XrmHashBucketRec *db; int (*synchandler)( /* Synchronization handler */ struct _XDisplay* ); char *display_name; /* "host:display" string used on this connect*/ int default_screen; /* default screen for operations */ int nscreens; /* number of screens on this server*/ Screen *screens; /* pointer to list of screens */ unsigned long motion_buffer; /* size of motion buffer */ unsigned long flags; /* internal connection flags */ int min_keycode; /* minimum defined keycode */ int max_keycode; /* maximum defined keycode */ KeySym *keysyms; /* This server's keysyms */ XModifierKeymap *modifiermap; /* This server's modifier keymap */ int keysyms_per_keycode;/* number of rows */ char *xdefaults; /* contents of defaults from server */ char *scratch_buffer; /* place to hang scratch buffer */ unsigned long scratch_length; /* length of scratch buffer */ int ext_number; /* extension number on this display */ struct _XExten *ext_procs; /* extensions initialized on this display */ /* * the following can be fixed size, as the protocol defines how * much address space is available. * While this could be done using the extension vector, there * may be MANY events processed, so a search through the extension * list to find the right procedure for each event might be * expensive if many extensions are being used. */ Bool (*event_vec[128])( /* vector for wire to event */ Display * /* dpy */, XEvent * /* re */, xEvent * /* event */ ); Status (*wire_vec[128])( /* vector for event to wire */ Display * /* dpy */, XEvent * /* re */, xEvent * /* event */ ); KeySym lock_meaning; /* for XLookupString */ struct _XLockInfo *lock; /* multi-thread state, display lock */ struct _XInternalAsync *async_handlers; /* for internal async */ unsigned long bigreq_size; /* max size of big requests */ struct _XLockPtrs *lock_fns; /* pointers to threads functions */ void (*idlist_alloc)( /* XID list allocator function */ Display * /* dpy */, XID * /* ids */, int /* count */ ); /* things above this line should not move, for binary compatibility */ struct _XKeytrans *key_bindings; /* for XLookupString */ Font cursor_font; /* for XCreateFontCursor */ struct _XDisplayAtoms *atoms; /* for XInternAtom */ unsigned int mode_switch; /* keyboard group modifiers */ unsigned int num_lock; /* keyboard numlock modifiers */ struct _XContextDB *context_db; /* context database */ Bool (**error_vec)( /* vector for wire to error */ Display * /* display */, XErrorEvent * /* he */, xError * /* we */ ); /* * Xcms information */ struct { XPointer defaultCCCs; /* pointer to an array of default XcmsCCC */ XPointer clientCmaps; /* pointer to linked list of XcmsCmapRec */ XPointer perVisualIntensityMaps; /* linked list of XcmsIntensityMap */ } cms; struct _XIMFilter *im_filters; struct _XSQEvent *qfree; /* unallocated event queue elements */ unsigned long next_event_serial_num; /* inserted into next queue elt */ struct _XExten *flushes; /* Flush hooks */ struct _XConnectionInfo *im_fd_info; /* _XRegisterInternalConnection */ int im_fd_length; /* number of im_fd_info */ struct _XConnWatchInfo *conn_watchers; /* XAddConnectionWatch */ int watcher_count; /* number of conn_watchers */ XPointer filedes; /* struct pollfd cache for _XWaitForReadable */ int (*savedsynchandler)( /* user synchandler when Xlib usurps */ Display * /* dpy */ ); XID resource_max; /* allocator max ID */ int xcmisc_opcode; /* major opcode for XC-MISC */ struct _XkbInfoRec *xkb_info; /* XKB info */ struct _XtransConnInfo *trans_conn; /* transport connection object */ }; |
Some of the Display members are explained in the following sections. For instance in section 1.3 we are introduced to buffer, bufptr and bufmax, that are discussed also in some other sections. Also in section 1.5 we show in some extend the process of the connection with the X Server via the XOpenDisplay() call. This routine fills many of the Display members. Other sections like section 2.5 also show the usability of some Display members.
The values of the Display members are examined in some of the following sections, mainly with the Gnu debugger (gdb). Consider for instance the following image from section 2.3, which shows the Display fields:
Struct Display is the handle of the X Client for the requests to the X Server. The members of Display indicate the specific X Server, that the client is connected (a.k.a. the 'display') and also provide information about the connection at the specific moment. For instance the memory location of the next messages that wait to be sent to the server. As we mention in section 1.5 from the user's perspective the display is the actual X Server that a client program gets connected. The display info is passed with the program name of the X Client at the command line, otherwise the DISPLAY environment variable provides the display value. Then XOpenDisplay(), the Xlib routine that makes the connection stores the 'display' value in the 'display_name' member of the Display struct.
In some programming examples in the following sections we use as example the X Client 'test' and we invoke this client from the command line providing the DISPLAY environment variable. For instance some of the commands we used to start test are the following:
./testor
DISPLAY=:0.0 ./testor
DISPLAY=unix/:0.0 ./testor
DISPLAY=tcp/192.168.1.101:0.0 ./testThe combinations we can use derive from the formula:
[protocol/] [hostname] : [:] displaynumber [.screennumber]Other X Clients, for instance the standard UNIX applications Xeyes, Xterm use the command line arguments to provide the display. This is usually the -display option.
From the source code of the test X Client program we see that after acquiring the Display - variable d in the example - this 'handle' is used for every client request to the X Server. For instance d is the first argument to XCreateSimpleWindow(), DefaultScreen(), XMapWindow(), etc. An X Client could be connected to different X Servers at the same time (the opposite is certainly true) and therefore the Display handle directs the requests, expressed as Xlib functions, to the correct server.
/* Simple Xlib application drawing a box in a window. To Compile: gcc -O2 -Wall -o test test.c -L /usr/X11R6/lib -lX11 -lm */ #include<X11/Xlib.h> #include<stdio.h> #include<stdlib.h> // prevents error for exit on line 18 when compiling with gcc int main() { Display *d; int s; Window w; XEvent e; /* open connection with the server */ d=XOpenDisplay(NULL); if(d==NULL) { printf("Cannot open display\n"); exit(1); } s=DefaultScreen(d); /* create window */ w=XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1, BlackPixel(d, s), WhitePixel(d, s)); // Prosses Window Close Event through event handler so XNextEvent does Not fail Atom delWindow = XInternAtom( d, "WM_DELETE_WINDOW", 0 ); XSetWMProtocols(d , w, &delWindow, 1); /* select kind of events we are interested in */ XSelectInput(d, w, ExposureMask | KeyPressMask); /* map (show) the window */ XMapWindow(d, w); /* event loop */ while(1) { XNextEvent(d, &e); /* draw or redraw the window */ if(e.type==Expose) { XFillRectangle(d, w, DefaultGC(d, s), 20, 20, 10, 10); } /* exit on key press */ if(e.type==KeyPress) break; // Handle Windows Close Event if(e.type==ClientMessage) break; } /* destroy our window */ XDestroyWindow(d, w); /* close connection to server */ XCloseDisplay(d); return 0; } |
As we mentioned in section 1.4.2 the display info, passed from the command line argument of the client program to the display_name member of Display indicates the specific X Server and demultiplexes the connection at the protocol layer (for instance tcp). For instance to run the X Client test for a tcp connection, that connects to the X Server at IP 192.168.1.101, the following command would be used:
DISPLAY=tcp/192.168.1.101:0.0 ./testNotice that :0.0 indicates the first X Server (if more than one exist) found at the specific IP and the first screen of this server (also if more than one screens are supported). At this case the X Server gets the port number 6000. In the case that the client gets connected to the second X Server found at 192.168.1.101 the command would be:
DISPLAY=tcp/192.168.1.101:1.0 ./testand this display info would result to a connection at IP 192.168.1.101, port 6001.
For an explanation on how the port numbers 6000, 6001, 6002, etc are formed see the internal mechanism of the X Server at subsection "The X Server's socket address - TCP/IP transport" in section 1.4.2 |
The protocol layer demultiplaxion, which for instance for the tcp protocol is based on the socket pair client IP, client port - server IP, server port is also resulted from the display info.
Consider for instance the following image:
The first of the two systems has IP 192.168.1.100 one X Server process and two X Clients (xclock and xcalc). The second system has IP 192.168.1.101 two X Servers and one X Client (xterm). The first X Server of the second system has two displays (:0.0 and :0.1). The first string means first server (0) and first screen (0) and the second string means first server (0) and second screen (1). Also the second X Server of the second system is indicated as :1.0, which means second X Server (1) and first screen at this server (0).
To use the second screen of the first server we could start the xclock process from the command line as:
DISPLAY=tcp/192.168.1.101:0.1 xclockThis would result to a connection with the 192.168.1.101 system at port 6000.
To get xterm connected at the X Server of 192.168.1.100 we would issue at the command line:
xterm -display=tcp/192.168.1.100:0.0This would result to a socket connection between the xterm client with client IP 192.168.1.101, client port number next available for a process in this system, server IP 192.168.1.100, server port number 6000.
To get xcalc connected at the second X Server of 192.168.1.101 the following command from the command line would be used:
DISPLAY=tcp/192.168.1.101:1.0 xclockThis instruction would result to the connection with the server socket: IP 192.168.1.101, port 6001.
REFERENCES:
Opening the Display