X Window Programming Manual: Chapter 2: X Concepts

来源:互联网 发布:报表数据分析公式 编辑:程序博客网 时间:2024/05/10 18:06

Chapter 2. X Concepts

This chapter introduces the concepts that underlie X programming.You should read this chapter even if you are the type of person wholikes to jump right into the code. (If you are desperate, you canskip ahead to Chapter 3 and return to this chapter when you getconfused.) “An hour or so spent reading about the system in generalcan save many hours of programming that leads to a dead end when theapproach turns out to be wrong.”

When learning a new programming language, many programmersprefer to look at a few code samples and then begin programmingright away, looking up more information as they need it. Thismanual is organized so that most of it is useful both as a tutorialand as a reference. There are lots of code samples and fragmentsin this manual to help the person who likes to read code more thanwords. Around the code they will find many of the concepts describedthat are necessary for understanding that particular example.

The “just-look-at-the-examples” approach works up to a point. Itallows a sharp individual to get “something” running in a very shorttime. Eventually, however, programmers find that in order to get themost out of a system--and sometimes even to get it do anythinguseful--a lot of underlying issues must be understood. In X,there are a lot of interrelated concepts and assumptions that areso basic that the programmer should know them cold. An hour or sospent reading about the system in general can save many hours ofprogramming that leads to a dead end when the approach turns outto be wrong.

This chapter describes those underlying issues and assumptionsthat are so important to programming with Xlib. It goes intoconsiderably more detail than the brief conceptual overview providedinChapter 1, “Introduction”After reading this chapter, you willbe well prepared to understand the rest of this manual and willhave a sound idea of what is required to write an X application.This chapter describes how Xlib works, including a description ofwindow concepts and characteristics, graphics, and events, and reviewsthe issues that you will need to think about in order to program.

How Xlib Works

Let's start by describing the problem that X was designed tosolve and then describe how it goes about solving it.

First of all, X was designed to provide windows on bitmappedterminals. This has been done before but not in a waydesigned to be easily portable to many different brands ofhardware, from PCs to supercomputers. The code was designedto stress easy portability, even between different operatingsystems, but still to allow high performance.

Second, X was designed to allow many different types of machinesto cooperate within a network. This was one of the majorinnovations in the X design. There are several standard networkingprotocols, but there was lacking a widely adopted standard for ahigher-level protocol specifying what should be sent over the networkto drive a window system. The first thing that was determined aboutX was the protocol used to communicate across the network.

Third, the developers of X decided that it should not require(or even imply) a particular style of user interface. Practicallyspeaking, X would not have been adopted as a standard by many companiesif it had implied a user interface incompatible with their proprietarywindow systems. In addition, the developers of X felt that the issuessurrounding the design of a window-based user interface for X werenot sufficiently worked out at present. An important design goal wasthus to make X “policy free.”

To accomplish these goals, the X Window System had to be designed fromthe bottom up. To work over a network, there had to be programs runningat both ends of the connection to send and receive the information andto interpret it. The end that controls the display and input deviceswas named the server. At the other end are clients--programs writtenusing Xlib to interface with the X protocol. This is shownin Figure 2-1.

Figure 2-1. Clients and servers

Actually, although this manual describes Xlib, the C language interfaceto the X protocol, there is also a Lisp interface, and there are likelyto be others. Any language binding that can generate and receiveX protocol requests can communicate with a server and be used withthe X Window System. But, at present, Xlib is the most popular low-levelprogramming interface used with X, because C is so widely available.

The X Protocol

The X protocol specifies what makes up each packet of informationthat gets transferred between the server and Xlib in bothdirections. Even when the server and Xlib are running on thesame machine, the protocol is used for communication,through some internal channel instead of the external network.There are four types of packets that get transferred via theprotocol: requests, replies, events, and errors.

A protocol request is generated by Xlib and sent to the server.A protocol request can carry a wide variety of information, suchas a specification for drawing a line or changing the colorvalue in a cell in a colormap or an inquiry about the currentsize of a window. Most Xlib routines generate protocol requests.The exceptions are routines that only affect data structures localto Xlib and do not affect the server (regions and the resourcemanager are the primary examples of these exceptions).

A protocol reply is sent from the server to Xlib in response tocertain requests. Not all requests are answered by replies--onlythe ones that request information. Requests that specify drawing,for example, do not generate replies. When Xlib receives a reply,it places the requested data into the arguments or returned valueof the Xlib routine that generated the request. An Xlib routine thatrequires a reply is called around-trip request. Round-triprequests have to be minimized in clients because they lowerperformance when there are network delays.

An event is sent from the server to Xlib and contains informationabout a device action or about a side effect of a previous request.The data contained in events is quite varied, because it is theprincipal method by which clients get information. Events are keptin a queue in Xlib and can be read one at a time by the client.The range of types of events that the server sends to a client isspecified by the client.

Anerror tells the client that a previous request was invalid.An error is like an event, but it is handled slightly differentlywithin Xlib. Errors cannot be read by the Xlib calls that readevents. Instead, errors are sent to an error-handling routine inXlib. The default error handler simply prints a message and exits;it can be replaced by a client-specific error-handling routine.

Buffering

Xlib saves up requests instead of sending them to the serverimmediately, so that the client program can continue runninginstead of waiting to gain access to the network after everyXlib call. This is possible because most Xlib calls do notrequire immediate action by the server. This grouping ofrequests by the client before sending them over the networkalso increases the performance of most networks, because itmakes the network transactions longer and less numerous,reducing the total overhead involved.

Xlib sends the buffer full of requests to the server under threeconditions. The most common is when an application calls an Xlibroutine to wait for an event but no matching event is currentlyavailable on Xlib's queue. Since, in this case, the applicationmust wait for an appropriate event anyway, it makes sense toflush the request buffer. Second, Xlib calls that get informationfrom the server require a reply before the program can continue, andtherefore, the request buffer is sent and all the requests acted onbefore the information is returned. Third, the client would like tobe able to flush the requestbuffer manually in situations where no user events and no callsto query the server are expected. One good example of this thirdcase is an animated game, where the display changes even when thereis no user input.

Let's look at how this works in practice.When the application starts up, all therequests that create the initial appearance of the applicationare queued up by Xlib. Then the application goes into itsevent loop and callsXNextEvent(). Since nothing has yetbeen sent to the server, there are no windows and therefore no eventshave yet been generated. SoXNextEvent() causes all therequests to be sent to the server, displaying the application.Meanwhile, the application is still waiting for the first userinput. When the user moves the mouse or presses a button or key, theserver, sends the events to Xlib as soonas the network allows--it does not queue them or groupthem (except under rare conditions involving grabs discussedin“Grabbing the Keyboard and Pointer” in Chapter 9). Normally, once an event arrives, theapplication generates more requests to draw--for example,highlighting the border of a button. These stay queued in Xlibuntil all the events that have already arrived have been processed.Once the application arrives atXNextEvent() and nomore events are in the queue, the queued requests are sent tothe server and the process starts again.

Using Xlib calls, the client can flush the connection in threeways: by calling a routine that requires an immediate reply (aroutine with Query,Fetch, or Get in itsname); by calling certain event-reading routines when no matchingevent exists on Xlib's queue; or by calling the routinesXFlush orXSync(). [4]The first of these actions says to the server, “I need some information;please act on these requests right away and then give me the information.”The second says, “I'm waiting for a certain kind of event, so I'll checkif you already sent the event over to Xlib. If not, please act on theserequests immediately, and then I'll be waiting for the event.” The lastone says, “I don't need any information from you now, but I need you toact on these requests immediately.” Normally, the last method is notused much because there are enough of the first two types of Xlibcalls in the client to make the transactions frequent enough.

You should already know that Xlib maintains a queue of the events for eachserver to which an application is connected, as shown in Figure 2-2.Whenever events arrive from the server, they are queued until theclient reads them.

Figure 2-2. The server's event queue and a client's event queue

The fact that Xlib queues both input and output is very important inapplication programming and especially in debugging. It means thatdrawing requests will not appear in a window until the request bufferis flushed. It means that errors are not discovered by the server untilthe requests arrive at the server and are processed, which happens only afterXlib flushes the request buffer. Once discovered, the error is reportedimmediately to the client. In other words, several Xlib routines may becalled before an error caused by an earlier routine is reported. Theseare two of the most visible examples of the effects of buffering.See“Debugging an X Application” for more details on how buffering affectsprogramming and debugging.

Resources

X uses several techniques to reduce network traffic. One majortechnique is to have the server maintain complex abstractionssuch as windows or fonts and have the client allocate an integerID number for each one as a nickname. Each of these abstractionsis called a resource. A resource can be a window, pixmap,colormap, cursor, font, or graphics context (these will bedescribed in a moment).

Whenever an operation is to be performed on a window (or anyother resource), the ID of the window is used in one argumentto the Xlib routine. This means that instead of an entirestructure full of data being sent over the networkwith an Xlib routine call, only a single integer that refers tothat structure need be sent. Remember that since the client andthe server may be running on different machines, pointers cannotbe used to refer to structures. The caveat of the resourceapproach is that the client must query the server when it needsinformation about resources, which, as mentioned above, leads tonetwork delays. As it turns out, clients normally do not need toquery the server very often, and the resource abstraction greatlysimplifies programs.

If any client knows the ID of a resource, that client can manipulatethat resource even if some other client created the resource.That means that more than one client can draw into the same window,although that is not often desirable. More importantly, thisis how window managers are implemented--they can move and resizeapplication windows because they know the IDs.

Be warned that there is another use of the term “resource” in Xthat pertains to the resource manager. A resource in the contextof the resource manager is a user-preference specification thatcontrols user-customizable elements of an application. Fortunately,these two uses of the term resource apply to differentparts of X and therefore are not too difficult to keep separate.One use applies to server-maintained data structures, and the otherto user customization of an application.

Properties and Atoms

The developers of X needed a way to allow clients to communicatearbitrary data with each other, and they came up with properties.Aproperty is a packet of information associated witha window, made available to all the clients running under aserver. Properties are used by clients to store informationthat other clients might need or want to know and to readthat information when set by other clients.

Properties have a string name and a numerical identifier calledan atom. An atom is an ID that uniquelyidentifies a particular property. Property name strings aretypically all upper case, with words separated by underscores,such as “WM_COLORMAP_WINDOWS”. Atoms are used to refer toproperties in routine calls so arbitrary-length property namestrings do not need to be sent over the network. An applicationgets the atom for a property by callingXInternAtom().You specify the string name for the property as an argument toXInternAtom(), and it returns the atom. From this pointon, the application uses only the atom to refer to that property.Every application that uses this procedure will get the sameatom for the same property name string, if it isconnected to the same server (that has not been reset).

Some atoms, called predefined atoms, are defined whenthe server initializes. An application does not need to useXInternAtom() to get these atoms. Instead, these atomsare available as symbolic constants beginning with XA_.These atoms identify properties whose contents have a certainmeaning known by convention to all clients. The propertiesthemselves do not have any contents until a client or the windowmanager sets them. Some of the properties described in thismanual have predefined atoms and others do not, for historicalreasons. Where predefined atoms are available, such asXA_WM_HINTS, we will use them in the text to refer tothe property. For properties with no predefined atoms, we willuse the string property name such as WM_COLORMAP_WINDOWS,which does not begin with XA_ and is not in Courier typeface.This tells you whether you will need to callXInternAtom()before using the property.

A group of related clients or an extension may define otherproperties and atoms that will have a meaning known to allthe clients in the group or using the extension.

Atoms for properties are analogous to the IDs used to refer toserver resources, except that both an atom and a window areneeded to uniquely identify a property. The same atom would beused to identify a property on one window as on another--onlythe window is different in the calls to set or read this propertyon two windows. Only the typeAtom is ever used in clientcode; properties are the underlying data managed by the server.

One of the most important uses of properties is to communicateinformation from applications to the window manager and vice versa.The application sets thestandard properties on its top-levelwindow to specify the range of sizes it prefers for its top-levelwindow and other information. These properties are called “standard”because they are the minimum set that an application should specify.Properties also communicate the other way; for example, the windowmanager specifies what sizes of icon pixmaps it prefers.

For more information on properties and atoms, see “Properties and Atoms” in Chapter 12

The Window Manager

The window manager is just another client written with Xlib, butby convention, it is given special responsibilities.It mediates competing demands for the physical resources of adisplay, including screen space and the colormap. Usually ithas a user interface to allow the user to move windows abouton the screen, resize them, and start new applications.

Most window managers decorate the main windows of all applicationswith a titlebar and various tools for iconifying and resizing theapplication. The window manager does this by creating a separatewindow that fits behind the main window of each application. Itis this separate window that has the decorations on it. This isimportant mainly because your application code does not need to handlethis drawing. Figure 2-3 shows the titlebar added to an applicationbytwm, the standard window manager in the MIT distribution as ofR4.

Figure 2-3. Titlebar added to applications by the twm window manager

Much of the communication between clients and the window managerand vice versa occurs through properties (the rest occurringthrough events). Many of the properties are known ashintsbecause they may not necessarily be honored by the window manager,even if one is running. An application must be prepared for thewindow manager to ignore, modify, or honor the preferences itindicates through the window manager hints. The propertiesthemselves do not have valid contents until applications orthe window manager set them.

Quite a few of the features of Xlib (and the Xprotocol) exist only to give the window manager the mechanism toenforce its authority. These are describedin Appendix L,Interclient Communcation Conventions,of Volume Zero (as of the second printing).They will not be needed by normal applications.

One such feature is calledsubstructure redirection.Substructure refers to the size, position, and overlappingorder of the children of a window. Redirection refers tothe requests by applications to change the configuration of thesewindows being sent to the window manager for approval instead ofactually getting acted upon by the server. Substructure redirectionallows a window manager to intercept any request by an applicationto change the size, position, border width, or stacking order (knowncollectively as the window configuration) of its top-level windowson the screen. Any application request to change the configurationof its top-level window will be canceled, and instead an event willbe sent to the window manager indicating the arguments used in thereconfiguration request. The window manager can then decide whatsize, position, and stacking order to grant the application, andthe window manager will reconfigure the window to those dimensions.For temporary windows such as pop-up menus and dialog boxes, thesubstructure redirect feature can be turned off using a window attribute.

Substructure redirection may seem obscure, but it has two significantimplications for applications. The first is that the applicationcannot assume that the configuration it specifies for a window willactually be reflected in the window on the screen. This is truewhether the configuration was set by creating the window or byreconfiguring the window. That means that the application mustalways determine the new configuration of the window before drawinginto it. It can do this by selecting a certain event type whichcontains the window configuration.

The second important implication of substructure redirection concernsthe mapping of a top-level window. Because the window manager canintercept the mapping request, and it might take some time before thewindow manager decides on a window configuration and maps the windowitself, an application cannot assume that the window is visibleimmediately. That means it cannot draw into the window immediately.The application must wait until it receives an event indicating thatthe window is visible before drawing into the window.

Communicating with the window manager, and window managementin general, is a long story which we'll describe more fullyinChapter 3, “Basic Window Program” and Chapter 12, “Interclient Communication” Chapter 16, “Window Management” gives an example of a simple windowmanager and describes communication with applications fromthe window manager's perspective.

Most window managers today also have the ability to start andkill applications. This is known a session management. However,they can usually start onlyxterm and a few other basic clients.A truesession manager can be a separate client. It would beable to start any client and control its command line arguments andsave the state of a whole group of clients (before the user logs out)and later restore them to the same position on the screen (when theuser logs back in). This level of capability is not yet available(but people are working on it). Each application supplies its commandline as a hint so that the window or session manager has enoughinformation to restart it in its current state.

Now you should have an idea of how Xlib works. Let's move onto a description of windows.

What are X Windows?

An X server controls a bitmapped screen. In order to make it easierto view and control many different tasks at the same time, this screencan be divided up into smaller areas called windows. A window is arectangular area that works in several ways like a miniature screen.Windows on the screen can be arranged so they all are visible or sothey cover each other completely or partially. A window may be any size greater than zero.

Each window (on a screen running X) can be involved in a differentactivity, and the windows currently in use are placed so they are atleast partially visible. The window manager lets you move a differentwindow to the top when necessary or rearrange the size and positionof the windows.

What you may not have realized is that some of these windows,such as the ones created by the mail handlerxmh, aremade up of many layered windows of various sizes. The scrollbars,titlebar, command buttons, and other features of the user interfaceare actually separate windows that provide information to the useror allow for input providing convenient control, as shown in Figure 2-4.There is more here than meets the eye.

Figure 2-4. The windows used to create an instance of the xmh application


Window Characteristics[5]

What are the characteristics of a window? There are many.

First of all, a window always has aparent window, which isassigned as the window is created. Each window is contained withinthe limits of its parent. The window cannot display output in areasoutside itself and cannot receive input from the keyboard or thepointer while the pointer is outside itself (unless a graborkeyboard focus is in effect,as described in Sections 8.3.2.1 and 8.3.2.2).Every window fits in a hierarchy set up by its children, its parent,its parent's parent, and so on. The very first window, the only onethat has no parent, is called the root window and fills the entirescreen. The root window is created by the X server as it starts up.

Second, each window has its own coordinate system. As shownin Figure 2-5, the origin of a window is the top-leftcorner of the window and the x and y coordinates increase tothe right and bottom.

In the X Window System:

  • The horizontal axis is x, and the vertical axis isy.

  • x and y are 0 at the upper-left corner inside theborder (if there is one) of the window currently in use. Thispoint is referred to as the window'sorigin.

  • Coordinates increase toward the right and bottom of the window.

  • Coordinates are integral and coincide with pixel centers.

All measurements for placing graphics and for positioningsubwindows are made from the origin. When we say that apoint isrelative to a window, this means that thex and y coordinates of the point are measured from thewindow's origin.

Each window is given a unique identifying number (ID) when itis created. All the routines that affect a particular windowuse a window ID as an argument and act in this window environment,so positions in the window are specified relative to the upper-leftcorner inside the border. It is not necessary to know the positionof a window to correctly locate subwindows or draw graphics withinthe window.

For example, to create a window usingXCreateWindow() orXCreateSimpleWindow(), you supply an offset from theupper-left corner of the parent to position the new window.When the parent moves, the new window stays in the sameposition relative to its parent.

Third, a window has aposition, which locates its upper-leftcorner relative to its parent's corner, a certainwidth andheight of usable pixels within the border, and aborder width.These characteristics are shown in Figure 2-5. By convention,the window width and height do not include the border. Since severalwindows may have the same parent, a window must also haveastacking order among these windows to determine which will bevisible if they overlap.These four characteristics are collectivelyknown as thewindow configuration because they affect the layoutof windows on the screen.

Figure 2-5. Elements of the window configuration

To summarize, the window configuration includes:

  • A window's width and height in pixels,not including the border.

  • A window's border. It can vary in width;zero makes the border invisible.

  • A window's particular position on the screen, specifiedby x and y in pixels, measured from the originof the parent (the upper-left corner, inside the border) tothe upper-left corner of the child, outside its border.

  • A window's particular stacking order among the windowswith the same parent.

The width, height, and position are collectively called thewindow geometry. Applications often allow users tospecify the geometry and border width of the window as acommand line argument or through the user defaults mechanism.

Fourth, a window has characteristics referred to asdepthand visual, which together determine its color characteristics.The depth is the number of bits available for each pixel to representcolor (or gray scales). The visual represents the way pixel valuesare translated to produce color or monochrome output on the monitor.

Fifth, a window has aclass of either InputOutputor InputOnly. As the names imply, InputOutputwindows may receive input and may be used to display output, andInputOnly windows are used for input only. There is nosuch thing as an output-only window because certain types of input,called events, are needed by all windows.

Sixth, a window has a set ofattributes. The window attributescontrol many aspects of the appearance and response of the window:

  • What color or pattern is used for the border and background ofthe window?

  • How are partial window contents relocated during resizing?

  • When are the contents of the window saved automatically as theybecome covered and then exposed?

  • Which event types are received, and which types arethrown away (not passed on to ancestor windows)?

  • Should this window be allowed to be displayed, moved, or resizedwithout notifying the window manager?

  • Which colormap is used to interpret pixel values drawn in this window?

  • Which cursor should be displayed when the pointer is in this window?

This may seem like a dizzying array of variables, but in practice,many of them default to reasonable values and can be safely ignored.And the flexibility they provide makes the system much more powerful.All of these window characteristics will be explained in more detaillater in this chapter, and most will be covered again later in the manual.

But first, a little more detail is necessary on the basic frameworkof X: the window hierarchy, the stacking order, and the concept ofwrapping. These are the subjects of the next three sections.

Window Hierarchy

Windows are arranged in a hierarchy like a family tree, except thatonly one parent is required to create a child window. There is aseparate hierarchy for each screen. At the top is therootwindow, which fills the entire screen and is created when the serverinitializes. The first windows to be created by each client arechildren of the root window. In the client's first call toXCreateWindow() orXCreateSimpleWindow() (either of which creates a new window),the root window is the parent.

The children of the root window are special, because they are thetop-level windows of each application and they are managed bythe window manager.Chapter 3, “Basic Window Program” describes the specialprocedures required of a client before displaying, moving, orresizing this window.

Each child may also have its own child windows. These child windowsof the top-level windows are used to create application featureslike command buttons and scrollbars.

Figure 2-6 shows a window hierarchy as it might appearon the screen, and Figure 2-7 shows the same hierarchy inschematic form. Note that the windowsA through Grepresent subwindows of each application, which may not overlaplike this in real applications. Normally the subwindows are usedas command buttons or panes which are laid out in non-overlappingfashion, as was shown in Figure 2-4. However, this hypotheticalhierarchy serves to demonstrate the effects of the stacking orderand the window hierarchy.

Figure 2-6. A sample window hierarchy on the screen


Figure 2-7. A sample window hierarchy in schematic form

A child may be positioned partially or completely outside itsparent window, but output to the child is displayed and inputreceived only in the area where thechild overlaps with the parent. Figure 2-6 shows that thechild windows do not extend beyond the borders of the parent evenwhen they are positioned in such a way that they would otherwiseoverlap the parent's edge. (For example, in Figure 2-6,windowG will not be drawn beyond the bottom of window3even if its height would suggest that it should.) If a window ismoved in such a way that it would extend beyond the parent, it isclipped, so that only the part overlapping the parent is displayed.

These are the terms used to describe subsets of the window hierarchy:

Parent 

The window used when creating a child window.

Child 

A window created with another window as parent.

Subwindow 

Synonymous with child. Not the same as descendant.

Siblings 

Windows created with the same parent (brothers and sisters).

Descendants 

The children of a window, their children, and so on. Descendantscould also be calledinferiors. This term is more inclusivethanchild or subwindow, since it can include severalgenerations in the window hierarchy.

Ancestors 

The parent of a window, its parent, and so on, including theroot window. Ancestors could also be calledsuperiors.

Window Stacking Order

When one window overlaps one of its sibling windows, the oneon top obscures part of the other. The stacking order determineswhich window appears on top. This order can be changed withvarious routines to raise, lower, or circulate windowsrelative to their siblings. These routines affect only a groupof siblings and their descendants but not their ancestors.

Child windows always stay in front of their parent. When a windowwith children is moved in the stacking order, all its child windowsmove with it, just as they do (because of the window-based coordinatesystem) when the parent is moved around the screen.

Figures 2-6 and 2-7 showed a set of windows on thescreen and their hierarchy, and if you look carefully, you can seehow the stacking order affects each group of sibling windows.Notice that window2 is above window C and all theother children of window1.

Mapping and Visibility

A newly created window does not immediately appear on the screen.It is an abstract entity that cannot be drawn to (unless a backingstore feature--discussed later in this section--is implementedon that server and turned on with the appropriate window attribute).Mapping marks a window as eligible for display. If it is notobscured by siblings or siblings of ancestors, it may be visible,and only then can it be drawn to.

XMapWindow() maps a window in its current position in the stackingorder, whileXMapRaised() places the window at the top of thestacking order of its siblings before mapping it. For a new window nevermapped before, these two calls are equivalent, since the initial stackingposition of a new window is on top.

You must map a window before you have any chance of seeing it, but thatalone is not enough. A number of factors can affect whether any window,newly created or already mapped, is visible:

  1. The window must be mapped withXMapWindow() or related routines.

  2. All of the window's ancestors must be mapped.

  3. The window must not be obscured by visible sibling windows or siblingsof ancestors. If sibling windows are overlapping, whether or not awindow is obscured depends on the stacking order. The stacking ordercan be manipulated withXCirculateSubwindows(),XConfigureWindow(), and XRestackWindows().

  4. The request buffer must be flushed by a routine that gets events,with a call toXFlush(), or by a function that requestsinformation from the server. More information on this topic wasprovided in“Buffering”

  5. The initial mapping of a top-level window is a special case, sincethe window's visibility may be delayed by the window manager due tosubstructure redirection that was briefly described in“The Window Manager”For complicated reasons, a client must wait for the firstExposeevent before assuming that its window is visible and drawing into it.It is not important to understand why this is true at this point.

An important consequence of these rules, and one of the reasons forthem, is that unmapping a window (withXUnmapWindow()) erasesthe window and all its descendants from the screen. X allows you(or, actually, the window manager) to control the placement andvisibility of an entire client made up of a hierarchy of windowssimply by manipulating the top-level window.

The window configuration and window attributes are maintained when awindow is unmapped. But it is important to remember that the X serverdoes not automatically preserve the visible contents of a window. Graphicoperations on a window that is not visible or that is unmapped have noeffect. Graphics visible in a window will be erased when that window isobscured and then exposed. For these reasons, it is important for theclient to be prepared to redraw the contents of the window on demand,as described in “Introduction to Events”

On some high performance servers, a “backing store” feature is availablethat maintains the window contents when a window is unmapped or coveredby other windows, so that the window is automatically refreshed with thecurrent contents when it becomes visible again. This feature is expensivein terms of computing resources and should be invoked only for windowswhose contents are difficult to recreate. On many types of equipment, thisfeature is not supported, so for the sake of portability, programs shouldbe capable of recreating the contents of their windows in other ways. Thisportability is particularly important in X, because network environments oftenemploy various brands of equipment.

Mapping is done with the XMapWindow() orXMapSubwindows() routines.Unmapping is done with theXUnmapWindow() orXUnmapSubwindows() routines.

Introduction to X Graphics

This section provides a brief introduction to the terms andconcepts used in graphics under the X Window System. You willsee these terms used in Chapters 3,Basic Window Program and 4, Window Attributesbefore we get to a serious treatment of graphicsin Chapters 5,The Graphics Context, 6, Drawing Graphics and Text, and 7, Color.

Pixels and Colors

The X Window System is designed to control bitmapped graphicsdisplays. In the simplest black-and-white display, there is asingle bit per pixel: the state of that bit determines whetherthe pixel will be black or white. In color systems or on monochromesystems allowing gray-scale displays, there are multiple bits per pixel.

The state of the multiple bits assigned to each pixel does not directlycontrol the color or gray-scale intensity of that pixel. Instead theyare used as an index to a lookup table called acolormap, as shownin Figure 2-8. On a color display, a pixel consists of separatered, green, and blue phosphors, each sensitive to a separate electronbeam; the relative intensity of these three colors fools the eye intothinking it sees a single color. Accordingly, the colormap containsan array of red, green, and blue (RGB) triples. In other words, ifthe value of the bits for a given pixel (apixel value) is 14,the RGB values of the fourteenth member of the colormap will bedisplayed at that location on the screen.

Figure 2-8. Mapping of pixel value into color through colormap

Each member of a colormap is called acolorcell, each ofwhich translates a pixel value into a specified set of red, green,and blue values. All bitmapped displays have at least one hardwarecolormap, though in the case of a single-plane monochrome screen, itmay consist of only two colorcells. In most cases, all clients sharethe single colormap by allocating only the number of colorcells theyneed and sharing as many as possible. When clients have specialrequirements, however, X allows them to have private colorcells orto create virtual colormaps which are then swapped into the hardwarecolormap (if it is writable) when necessary.

Note that each window can potentially specify a different colormap.This is the significance of the fact that the colormap is a windowattribute.

Pixels and Planes

The number of bits per pixel is also referred to as the number ofplanes in the graphics display. Black-and-white systems have asingle plane, color displays have from 4 to 28 planes, and gray-scaledisplays usually have from 2 to 4 planes. X11 supports up to 32 planes.

As can be inferred from the previous discussion of bits per pixel asan index to the colormap, the number of possible colors or shades ofgray that can besimultaneously displayed on the screen is2n, wheren is the number of planes in the display. (Of course,additional colors can be made available even on a system with onlya few planes, at the cost of existing colors, simply by loadingdifferent RGB values into the hardware colormap if it is writable.)

All graphics calculations are performed on the pixel values beforethey are translated into RGB. Thesource pixel valuesspecified in a drawing request and theold destination pixelvalues are combined according to a plane mask, clip mask, and logicalfunction to arrive at the finaldestination pixel values. Theplane mask, clip mask, and logical function are aspects of a structurecalled the graphics context (GC) and are described inChapter 5, “The Graphics Context”

The macros BlackPixel() and WhitePixel() return pixelvalues that map to black and white using the default colormap forthat screen. These macros are intended for use in monochromeprograms so that they will work on monochrome, gray-scale, or colordisplays. On color hardware,the colors of black and white may not actually be black and white,but they are guaranteed to be contrasting.

Pixmaps and Drawables

A window is not the only valid destination for drawing. Pixmaps arealso valid destinations for most graphics requests. Apixmapis a block of off-screen memory in the server. Windows and pixmapsare collectively known asdrawables.

A pixmap is an array of pixel values. It has a depth just like a window.It does not, however, have a position relative to any other window orpixmap, and it does not have window attributes such as a colormap. Allof those things affect a pixmap only when it is copied into a window.And a pixmap becomes visible only when copied to a window.

There are several routines for creating pixmaps. The simplest isXCreatePixmap(), which creates an empty pixmap with undefinedcontents. Always remember to clear a pixmap created withXCreatePixmap() before using it, otherwise it may contain garbage.Several others create pixmaps and fill a pixmap from data stored ina file. These functions will be mentioned later in the context ofthe various uses of pixmaps.

Some routines operate only on pixmaps or only on windows. Theseroutines specify eitherPixmap or Window as theargument. If either is allowed, the argument to the Xlib routinewill be specified as aDrawable. All the drawing routinesspecify the Drawable argument type.

A pixmap is not susceptible to being covered by other windows.Windows, on the other hand, may only be drawn to usefully whenthey are visible, since their contents are not maintained whenthey are obscured or unmapped (unless the backing store featureis available and in effect).

To be copied to a window with XCopyArea(), a pixmap musthave the same depth as the window it is to be copied to. Oncecopied, the colormap associated with the window is used totranslate the pixel values from the pixmap to visible colors.After copying, additional drawing into the pixmap does notappear in the window. A single plane of a pixmap of any depthcan be copied into any window withXCopyPlane().

In short, windows have the disadvantage that, when they are notvisible, drawing to them will not do anything. A pixmap, whichrepresents an area of the screen, resides in memory and can bedrawn to at any time. Unfortunately, pixmaps must be copied intoa visible window before the user can see them. This copying canhave performance penalties. Perhaps more importantly, off-screenmemory in the server used for pixmaps may be limited in quantity.Therefore, programs that use a lot of pixmaps may not work on PCservers and X terminals.

A pixmap of depth 1 is known as abitmap, though thereis no separate type or resource called Bitmap. A bitmap is atwo-dimensional array of bits used for many purposes includingcursor definitions, fonts, and templates for two-color pictures.Each bit represents a single pixel value that is either set (1)or unset (0). Depending on the visual type, these pixel valuescan be interpreted as two colors or simply as black and white.

Drawing and the Graphics Context

As in any graphics language, X provides routines for drawing points,lines, rectangles, polygons, arcs, text, and so on. Routines thatdraw graphics are generically calledgraphics primitives.But in X, a given graphics primitive does not contain all theinformation needed to draw a particular graphic. A server resourcecalled the graphics context (GC) specifies the remainingvariables, such as the line width, colors, and fill patterns. TheID of a GC is specified as an argument to the drawing routine andmodifies the appearance of everything that is drawn into the drawable.

The GC must be created by the client before any drawing is done.The created GC is stored in the server, so that the informationit contains does not have to be sent with every graphicsprimitive--only its ID is passed. This improves the performanceof drawing significantly since it reduces the traffic over theconnection between Xlib and the server. All GC settings apply toall graphics drawn using that GC.

More than one GC can be created, and each can be set with differentvalues. This allows a program to switch between GCs and get differenteffects with the same graphics primitive.

Tiles and Stipples

When pixmaps are used for patterning an area, such as for thebackground of a window or in a GC, they are often referred toas tiles or stipples.

A tile is a pixmap with the same depth as the drawable itis used to pattern. The tile is typically 16 by 16 pixels butcan be other sizes--certain sizes are drawn faster--dependingon the hardware (seeXQueryBestTile()). It is typicallycomposed of only two different pixel values since this is theeasiest type to create, but multiple pixel values are permitted.Areas drawn by any of the drawing routines can be tiled by placingcertain values in the GC. The background and border of windowscan be tiled by specifying a pixmap in the window attributes.

A stipple is a pixmap of depth 1. A stipple is used inconjunction with a foreground pixel value and sometimes abackground pixel value to pattern an area in a way similar to atile. There are two styles of stippling that can be set in thegraphics context. In one, set bits in the stipple are drawn inthe foreground color and unset bits are drawn in the backgroundcolor. In the other, only the set bits in the stipple are drawnin the foreground pixel value, and the pixels in the destinationrepresented by unset bits in the stipple are not changed. Liketiling, stippling affects only those pixels that are selected bythe graphics request, such as the pixels drawn for a line or acharacter. Stipples are only present in the GC and cannot beused for window backgrounds.

Figure 2-9 shows how a tile is used to pattern thebackground of a window.

Figure 2-9. Tiling of a window background


More on Window Characteristics

This section expands on the overview of window characteristicsin “Window Characteristics” and describes in more detail the windowattributes, window configuration, class, and depth and visual.

Window Attributes

The window attributes consist of information about how awindow is to look and act. Each window has a separate set ofattributes, which can be set withXChangeWindowAttributes()or, in some cases, with routines that change individual attributes.The attributes control the following window features:

Background 

Can be a solid color, a tiled pixmap, or transparent.

Border 

Can be a solid color or a tiled pixmap.

Bit Gravity 

Determines how partial window contents are preserved when a windowis resized.

Window Gravity 

Determines how child windows are relocated when a window is resized.

Backing Store 

Provides hints about when a window's contents should be automaticallysaved while the window is unmapped or obscured, which display planesshould be saved, and what pixel value is to be used when restoringunsaved planes. Not all servers are capable of backing. Check thevalue returnedfrom theDoesBackingStore() macro to determine whether thisfeature is supported on a particular screen on your server.

Saving Under 

Provides hints about whether or not the screen area beneath a windowshould be saved while a window, such as a pop-up menu, is in place tosave obscured windows from having to redraw themselves when thepop up is removed. Not all servers can save under windows. Youcan find out whether this feature is supported on a particularscreen with theDoesSaveUnders() macro.

Events 

Indicate which events should be received and which events shouldnot be sent to ancestor windows.

Substructure Redirect Override 

Determines whether this window should be allowed to be mappedon the screen without intervention by the window manager. Thisoverride is usually done for menus and other windows that arefrequently mapped and then almost immediately unmapped again.

Colormap 

Determines which virtual colormap should be used for this window.

Cursor 

Determines which cursor should be displayed when the pointer isin this window.

It may clarify the picture to describe the features that windowattributes do not affect. Setting the window attributesdoes not determine the size or position of a window, its parent,or its border width; these comprise the window configuration.Setting the window attributes does not affect the depth, class,or visual of a window; these are permanently set when the windowis created. Attributes do not determine how graphics requestsare interpreted; this is the job of the graphics context (GC).

Window Configuration

A window's configuration consists of its position, width andheight, border width,and stacking position, as described in “Window Characteristics” Thesefactors are handled differently from the window attributes (eventhough they are stored internally in theXWindowAttributesstructure) for an important reason: changing the configuration ofa top-level window (a child of the root window) must be done incooperation with the window manager.

We will not go into detail here about how the application mustinteract with the window manager when attempting to map a windowor change a window's configuration. For now, suffice it to saythat there are certain rules the application must follow so thatthe window manager can be responsible for controlling what is onthe screen and where. SeeChapter 3, “Basic Window Program” for anintroduction to client-window manager interactionandChapter 12, “Interclient Communication” for a complete description.

Class: InputOutput and InputOnly Windows

The X Window System provides two classes of windows: InputOutputand InputOnly. The main difference between the two classesis that an InputOnly window cannot be used as a drawable(a destination for a graphics request). Consequently,InputOnlywindows have a more limited set of window attributes, have no borderand a transparent background, and cannot haveInputOutputwindows as children.

InputOnly windows make an invisible area of the screen inwhich input has a different purpose but the display is not changed.InputOnly windows usually are assigned a different cursorto distinguish them.InputOnly windows are rarely used.

The class of a window is assigned at creation and cannot be changed.

Depth and Visual

The depth and visual of a window are assigned at creation andcannot be changed. The depth is the number of planes thatare to be used to represent gray scales or color within a window;depth is also the number of bits per pixel. The maximum depthallowable for an InputOutput window is the number ofplanes supported by the screen with which it is associated. Ifa screen has 12 planes, a window may have at most 12 bits perpixel, and therefore there are at most212possible different shades of gray or color.

The depth of an InputOnly window is always 0.ForInputOutput windows, the symbol CopyFromParent,when used as thedepth argument in XCreateWindow(),copies the depth of the parent window. Most windows use thedefault depth, inherited from the root window.

The visual accounts for the differences between various typesof display hardware in determining the way pixel values are translatedinto visible colors within a particular window. A screen may supportonly one visual or several types of visuals. AnXVisualInfostructure contains all the information about a particular visual.One member ofXVisualInfo is the visual class, which has oneof the values DirectColor,GrayScale, PseudoColor,StaticColor,StaticGray, or TrueColor.These values specify the characteristics of the colormaps that can beused with the window--whether the colormap is read-only or read/write,color or monochrome, split into three primary colors or composite.Other members ofXVisualInfo specify the valid range of pixelvalues; how many bits of the pixel are allocated to red, green, andblue; and several other variables.

Both the depth and visual are inherited from the parent when awindow is created withXCreateSimpleWindow(). For moreinformation on the visual class, seeChapter 7, “Color”

Icons

An icon is a small marker window that indicates that a larger“main” window exists and is available but is not currently mappedon the screen.

Most window managers allow the user to iconify an applicationto get it out of the way without destroying it. Deiconifying anapplication is faster and more convenient than running the applicationfrom scratch. Also, the iconified application keeps running whateverprocesses it was at work on when iconified (unless the application isprogrammed to halt when it is iconified). When input is required, theprogram may either wait until the window is deiconified or accept inputin the icon.

Figure 2-10 shows an xterm window before and after it isiconified. Thexterm application does not create an icon pixmap,and therefore, the window manageruwm simply draws its icon nameinto the icon. The appearance and placement of icons varies betweenwindow managers.

Figure 2-10. An application and its icon

Icon windows are managed and, in many cases, created by the windowmanager. Through the window manager hints (which will be detailedin“Communicating with the Window Manager” in Chapter 3 andChapter 12, “Interclient Communication”), an applicationpasses its icon's name and pixmap to be displayed in the icon window.If an application needs to perform operations on its own icon window(perhaps to be able to change the background at any time, as the mailhandler xmh does to indicate that mail has arrived), it cancreate its own icon window and pass the window ID to the windowmanager. Otherwise, the window manager will create the icon window.

The window manager may specify in a property on the root window whatsizes of icon pixmaps it prefers. If this property is set, theapplication should attempt to provide an icon pixmap of an acceptablesize. The window manager may also specify where icons will be placed.These are optional features of the window manager that may not bepresent. In fact, most current window managersdo not specify icon sizes or control icon location.

Special Characteristics of the Root Window

The root window is created when the X server program is initialized.The root window's characteristics differ slightly from those of otherwindows.

The root window is anInputOutput window. It is always mapped.Its size cannot be changed. Its upper-left corner is always at theupper-left corner of the screen, where the global coordinates are(0,0). The root window has a zero-width border. Its size isaccessible through macros that will be described in Chapter 3, “Basic Window Program”

The default window attributes of the root window include abackground pixmap with diagonal cross-hatchings, the defaultcolormap, and a default cursor that is a large X. Any of thesecan be changed. The event mask attribute can be changed, but bydefault, no events that occur in the root window are sent to anyclient. None of the other attributes are applicable to the rootwindow. SeeChapter 4, “Window Attributes” for more information onsetting window attributes.

The root window is never iconified by the window manager, becauseamong other reasons, it cannot be unmapped.

Introduction to Events

This section provides a brief introduction to events. You willneed this knowledge to fully understandChapter 3, “Basic Window Program” andsome of the window attributes described inChapter 4, “Window Attributes”Events are covered completely in Chapter 8, “Events”and Chapter 9, “The Keyboard and Pointer”

What is an Event?

Moving the pointer or pressing a keyboard key causes an input eventto occur. These are two of the simplest and most common event types,but there are many others. An event is a packet of information that isgenerated by the server when certain actions occur and is queued forlater use by the client. The queued events can be read at any subsequenttime in any order, but they are usually read and processed in the orderin which they occurred.

Here are some other sorts of events:

  • Mouse (or other pointer) button pressed or released.(ButtonPress, ButtonRelease)

  • Window mapped or unmapped. (MapNotify, UnmapNotify)

  • Mouse crossing a window boundary. (EnterNotify, LeaveNotify)

These event types are usually used for user input and to controla user interface.

A second group of events reports side effects of window operations.For example, when a window becomes visible after being obscured,it receives anExpose event. When window gravity (a windowattribute that controls the position of a window when the parent isresized) takes effect, aGravityNotify event is generated.

A third purpose of events is to allow various clients to communicatewith each other and with the window manager. The events that reportthe following actions are usually used for the second purpose.

  • A client may request that all keyboard input be sent to aparticular window regardless of the pointer position; this is calledakeyboard focus window. Changing keyboard focus from one windowto another causesFocusIn and FocusOut events, indicatingto the client whether or not it can expect further keyboard events.

  • Changing the mapping between keyboard keys and codes they generatecauses a MappingNotify event to be sent to all clients.

  • Reparenting a window is sometimes done by the window manager toadd a frame to windows on the screen. This action causes aReparentNotify event.

  • A PropertyNotify event is generated when a client changes aproperty on a window.

  • SelectionClear, SelectionNotify, and SelectionRequestevents are used to communicate back and forth between a client that isallowing a user to select a section of text (or other information) and aclient that is allowing the user to place the information in its window.Some of these events are sent with XSendEvent.

At this point, it is only important to understand in general whatevents are, not precisely what each one is for or how to use them.Chapter 8, “Events” and Chapter 9, “The Keyboard and Pointer”will provide complete details.

Selection and Propagation of Events

A client must select the event types that it wants the serverto send for each window. The selection is made by callingXSelectInput(), which sets theevent_maskwindow attribute, by setting that attribute with the more generalXChangeWindowAttributes() routine, or when callingXCreateWindow().

For example, a scrollbar may require mouse button events but notkeyboard events, while the main window of an application may requirekeyboard but not mouse events. One would select different event typeson each of these windows.

Keyboard and pointer events are generated in the smallest windowenclosing the pointer (or grabbing the pointer, as discussedin“Keyboard and Pointer Grabbing” in Chapter 8). Then an event of one of these types (only)propagates upward through the window hierarchy until the event typeis found in theevent_mask or do_not_propagate_maskattributes of the window. If the event is found in an event_maskfirst (or in both on the same window), then the event is sent as if itoccurred in that window, and if it is found in ado_not_propagate_maskfirst, then it is never sent. The ID of the window that finally receivedthe event (if any) is put in thewindow member of the event structure.

The do_not_propagate_mask can only be set withXChangeWindowAttributes() orXCreateWindow().Events other than keyboard and pointer events do not propagate.They occur in the window in which they were selected when theappropriate action occurs.

For most types of events, a copy of an event can be sent to morethan one client if each client has selected that event type on thatwindow. Each client has its own event mask for each window. Theclient that created the window need not do anything to cooperate.The second client that wants to get an event from a window that itdid not create simply needs to find out the ID of the window andthen select the desired event types withXSelectInput() onthat window.A duplicate event is sent to each window, and these events propagateindependently up through the hierarchy in the two applications. Thisis rarely done, because there is usually no reason for any program otherthan the window manager to play with another application's windows.

The Event Queue

What do we mean when we say that an event is queued? Each client hasits own event queue which receives the selected events in the order theyare sent by the server, as was shown in Figure 2-2.

The client then can remove each event at any time and process it accordingto its type and the other information in each event structure. There areseveral functions that get input, and they differ in how many windows aremonitored and what types of events are sought. The client can also readevents on the queue without removing them, remove one and then put it back,or clear the queue by throwing away all the events. Events can also becreated by a program and sent to the window manager or other programs.

An Event Structure

Expose is one of the most important event types, and its eventstructure is shown in Example 2-1. It is generated when anarea of a window becomes visible on the screen and indicates that theclient must redraw that area. This happens when a window is mapped,moved, resized, or deiconified or when an obscuring window is unmapped.Exposure events are common and can happen at any time, since they may becaused by the actions of other clients.

Example 2-1. An event structure

typedef struct {   int type;   unsigned long serial;   /* # of last request processed by                            * server */   Bool send_event;        /* True if this came from a SendEvent                            * request */   Display *display;       /* Display the event was read from */   Window window;   int x, y;   int width, height;   int count;              /* If nonzero, more expose events                            * follow */} XExposeEvent;


The type of event is reported in every event structure--in theXExposeEvent structure, thetype field would be thesymbolic constant Expose. The window to which the eventpropagated is reported in thewindow member, present in allbut five event types (those dealing with selections and graphicsexposure). All other information in the event structures isspecific to certain event types and is described in detail inAppendix E,Event Reference.

The Event Loop

Because events can arrive in any order, the structure of code tohandle them is predetermined. Every program contains an event loopin which each event is received and processed. Normally this loopis implemented as an infinitewhile loop, beginning with anevent-getting routine and followed by a switch statementthat branches according to the event type. Within each branch foran event type, there may be additional branches corresponding to thewindow in which the event occurred or other fields in the event structure.

The loop will almost always include exposure events. X does notnormally keep track of the contents of the obscured regions of windows.It is the responsibility of the program to make sure that the windowcontents can be redrawn when exposure occurs. The program must beprepared to receive and act on an exposure event at any time, meaningat every invocation of the event-gathering routine. A program may workperfectly as long as there are no other programs running, but that isnot good enough in a window environment!

When a window is first mapped, the first function of the programmust be to read the exposure event that is generated by mappingthe window. Then the program can draw the window's contents. Asit turns out, this is also how the program should respond when anexposure event arrives at any later time. The first drawing andlater redrawing are done in exactly the same way, using the same code.

Note, however, that another type of event, ConfigureNotify,must be handled in case the window manager modified the size of theapplication before mapping it and in case the user later resizes thewindow. More will be said about this inChapter 3, “Basic Window Program”

How to Program with Xlib

This section reviews what is important to know about X programmingbefore you write any code. Describing what goes into the designing,writing, and debugging of X programs should give you a better startwhen you begin your own programming.

The basic program described in Chapter 3, “Basic Window Program” illustrates manyof the issues described here.

Designing an X Application

Let's begin by outlining the major tasks any X application must perform.

From the user's standpoint, almost any application under any windowsystem will do the obvious things: create a window on the screenof an appropriate size, determine a position for some text and/orgraphics within the window, draw into the window, and accept keyboardand/or pointer input, changing the screen accordingly. Essentially,the top-level window of the application is treated very much like thewhole screen would be treated on a PC. These tasks are straightforwardand most programmers should find them familiar.

There are, of course, a few complications resulting from theunique features of window systems in general and the X WindowSystem in particular. These complications determine the designrequirements for an application that is to run under X.

Design Requirements

The following four paragraphs describe the things X applicationsmust do that are not obvious. These are things that must be donefor the application to operate properly under X but that theaverage user might not notice or know about.

First, X allows workstations to be connected in a network inwhich any host or node may run X programs and display them on anyother node, given permission. This means that the program must beable to accept the user's specification of which display to use.(Remember that each display has its own server, so choosing thedisplay is equivalent to establishing the connection between theclient and a particular server.) This requirement turns out tobe built in and requires virtually no programming, as is describedin “Connecting to a Server” in Chapter 3

Second, the application must be responsible in its use of the limitedresources of the display, chiefly screen space and colormaps. This isbecause there may be many applications running concurrently on a singlescreen, sharing those limited resources. The client in charge ofmanaging these limited resources is the window manager. There arecertain requirements for communication between each application and thewindow manager to ensure that competing needs can be fairly arbitratedand to help make sure that the user sees a consistent user interface.These requirements are not difficult to meet for simple applications,but they get more complex for serious applications. This area isdescribed inChapter 12, “Interclient Communication”

Third, other clients may be moved over your client and then movedaway, requiring your client to redraw its window or windows. X cannotmaintain the contents of an unlimited number of overlapping windows,and it is inefficient for it to try to maintain even a few. Yourclient will be told when redrawing is necessary and in what areas.This requirement is not hard to meet, but it encourages programmingin a way that records the current “state” of each window so that itcan be redrawn. The handling of exposure isdescribed in “Setting Up an Event-gathering Loop” in Chapter 3

Fourth, the user may resize your application, so it should be capableof recalculating the dimensions and placement of subwindows andgraphics to fit within the given window.

In a nutshell, these four aspects are all that is required of anX program beyond its basic functionality. Fortunately, for mostclients without unique needs such as a custom colormap, theserequirements are straightforward to satisfy.

The User Interface

The first step in designing an application will be to determine whatits features will be. Determining how the user will invoke thosefeatures is probably the next step. This means designing a userinterface.

X was purposely designed to be “policy free,” and therefore it doesnot come with a standard user interface like many other window systemsdo. You will have to write all parts of the user interface yourself,unless you choose to use one of the toolkits that are available. Usinga toolkit makes building a user interface much easier and is stronglyrecommended. Otherwise, you must write menus, command buttons, dialogboxes, and so forth and determine how they are to be used. Althoughthere are many ways to write these user interface features, there isa simple implementation of a menu in the winman program shownin Chapter 16, “Window Management” and an example of a dialog box routinein Chapter 9, “The Keyboard and Pointer” The writing of a command button routineshould be straightforward.

The key elements that interact in the design of a user interfaceare the hierarchy of windows and the selection and processing ofevents, chiefly pointer and keyboard events. Since these deviceevents propagate through the hierarchy depending on whether theyare selected for each window, both the hierarchy and the selectiontogether determine how events are received. For every user action,there must be a path (possibly unique, possibly common for severaldifferent user actions) through the event-handling code that yieldssome sort of response to the user, either by a visible change, amessage, or a beep. Therefore, the job of the event loop is todistinguish all the possible user actions and invoke the proper code.In the main event loop, each case statement for an event type mustthen have another switch, depending on the window which received theevent, before calling the function that performs the action the userrequested. The event type and the window in which it occurred areonly two of the most common event structure members--there may beadditional switch statements based on other members, too, such as whichkeys or buttons were being held while a key or button press occurred.

Especially for complex programs, a careful design of the windowhierarchy and selection of events can simplify the code and savehours of debugging. We recommend drawing out the hierarchy ofwindows and the types of events selected by each one and thendrawing in the eventsthat will be propagated to ancestor windows.This helps find problems before any code is written.

Writing an X Application

The best way to start writing an X application is probably tocopy the existing application that is most similar to your intendedpurpose or to start from a skeleton program such asbasicwin,described in Chapter 3, “Basic Window Program”Select one from the core portion of the standard distribution fromMIT, because these are the most likely to follow current conventions.

The following sections describe some basic facts about the actualprocess of coding and compiling an application.

Resources and User Customizability

An application should not hardcode all the options that are possibleunder X, such as colors and fonts. It should allow the user tospecify the colors of all windows, the font to use, the display andscreen to use, the initial size and position of the application,and a large number of other standard and application specific options.

An application should provide command line options, but there aretoo many variables to support all of them as command line options.The developers of X have designed a better way for the user tospecify options, called resources. The user places the desiredoptions in a file using a particular format and runs the Xapplication xrdb specifying this file as a command lineargument.xrdb places a property on the root window whosevalue is the contents of this file. Applications use a set ofXlib routines collectively called the resource manager to returna setting for each variable required. The routine XGetDefault()makes this process quite easy for the application. If the userhas not calledxrdb to set the property on the root window,XGetDefault() reads in a file called.Xdefaults inthe user's home directory. The application itself should containa default value for each variable in case neither of these sourcescontains a value for one of them.

This use of the term resource is completely different fromthe term server resource, which refers to windows and GCs.

A resource specification is a key/value pair. A key/value pair mayapply only to a particular window within a particular application,to an entire application, to a certain class of applications such aseditors, or to all applications. The algorithm used to find the valuefor a particular variable operates quite differently from a normaldatabase manager. Given an incomplete specification of a key, it usesan algorithm to determine which of the keys in the resource database isthe best match and returns the indicated value. It always returns onlyone value. This is much different from a normal database manager whichwould return many values if the key were too general.

The resource manager and providing user customizability aredescribed in detail inChapter 13, “Managing User Preferences”

Compiling and Linking X Programs

To use all the functions in the X library, you need to include<X11/Xlib.h>, <X11/Xutil.h>, <X11/keysym.h>,and <X11/Xresource.h>. These files define data structures,macros, and symbols and declare the types of functions. It isalso a good idea to include <X11/Xos.h>, which includescertain header files commonly used in C programs that differin name or location between various operating systems, notablySystem V and BSD. To compile and link your program with allthe available Xlib libraries, including a symbol table for asymbolic debugger, use:

cc -g -o outputfile inputfile.c -lX11

The -lX11 option specifies linking with the standardX library, Xlib.

A set of routines to make it easier to port programs from X Version 10to Version 11 is provided in a separate library. To use theX Version 10 compatibility functions, include <X11/X10.h> inyour source file and link with both the -lX11 and-loldXoptions to your cc command. You may wish to include<X11.Xos.h> if you use system calls, file manipulation, orstring manipulation utilities. This header file includes the rightfiles for various operating systems.

Several other libraries are available in the X distribution fromMIT: Xmu, the miscellaneous utilities library, and Xext, theextensions library (which requires additional server-side softwarein order to function). These are not yet adopted standards of theX Consortium but are widely available. If you use -lXmu, itmust be placed before Xlib on the compiling command line. All toolkitlibraries based on Xlib such as Xt must also appear before-lX11on the command line. -lXext can appear before or after-lX11 because it does not use Xlib.

If, when compiling, you get errors about header files in<X11/Xos.h> not being found, you are probably on a System Vsystem that does not define the symbolSYSV. To solve thisproblem, add -DSYSV to the command line.

You will probably want to usemake(1) when compiling timecould be saved by compiling smaller functions separately beforelinking. (For more information, see the Nutshell HandbookManaging Projects with Make.)Even better is to use make in combination withimake,which generates makefiles from a portable description file.imake is provided with the X distribution. For more informationseeThe X Resource, Issue 2, Spring 1992.

Naming Conventions

There are a number of conventions for the naming of Xlib functionsand constants. You should be familiar with these conventions inorder to name your own functions and constants properly. The majorconventions are:

  • The names of all Xlib functions begin with an X (capital x). Compoundwords are constructed by capitalizing the first letter of each word.For example, a typical function name isXAllocColor().

  • The names of most user-visible data structures and structure typesbegin with an X. The only exceptions areDepth, Display,GC, Screen, ScreenFormat, andVisual.Pointers to these six structures are quite commonly used in programs,but their members should not be accessed except through pre-existingmacros.

  • The names of all members of data structures use lower case. Compoundwords, where needed, are constructed with underscores (_).

  • The names of macros do not begin with an X. To distinguish macrosfrom user symbols (which are all caps), the first letter of eachword in the macro is capitalized. (The macros used for quarks arean exception to this rule, perhaps because they were once part ofa separate library. Their names begin with Xrm.)

  • The names of symbolic constants defined in X header files (#defined)use mixed case, with the first letter of each word capitalized, anddo not begin with X. Lowercase symbols are reserved for variablesand all uppercase for user symbols, according to existing convention.The only exception is that predefined atom names use all uppercaseletters, with underscores separating the words. Atom names beginwithXA_ to distinguish them from user symbols.

You should choose constants and routine names that will not beconfused with standard Xlib functions, macros, or constants. Userfunction names should not begin with X and perhaps should have thefirst letter of the first word lower case to avoid confusion withXlib macros. User constants should be all upper case. Variablenames can be lower case as usual, with underscores separating thewords if desired, since X structure member references will alwaysbe accompanied by the variable declared as the structure.

Using Structures, Symbols, and Masks

Xlib programming takes advantage of many structure definitions anddefined constants. This style of programming may be unfamiliar tosome programmers. We will describe how structures and constants aretypically used so that the idea will be familiar when you see the examples.

Pointers to structures are the major way of specifying data to andreturning data from Xlib routines. If the routine returns data, thereturned value will be a pointer to the data structure, unless theroutine returns more than one structure, in which case one or all ofthe structures will be arguments. In some routines (primarily thoseconcerning color), a pointer-to-structure argument specifies someinformation and returns some other information.

When setting the characteristics of a server resource, such as a set of windowattributes, a graphics context, the cells in a colormap, or a hardwarecharacteristic (such as key click), both a structure and a mask arespecified as arguments. Themask specifies which values in thespecified structure should be read when updating the resource values.One bit in the mask is assigned to each member in the structure, anda special constant is defined in the Xlib header files to representthat member when constructing the mask. Each of the mask constantshas one bit set. The mask argument is made by combining any numberof the mask constants with the bitwise OR operator (|). Forexample, the CWBackgroundPixmap constant is used to indicatethat the background_pixmap member of the specified windowattributes structure is to be read and the corresponding member in theresource changed.

The other major use of defined constants in Xlib (other than for masks)is as values for structure members themselves. They indicate which ofa number of alternatives is true. For example, several of the structuremembers can have only the valuesTrue or False. Asanother example, the type member of each event structure canhave one of 33 different values, each represented by a different definedconstant such asExpose. Defined constants are also used asreturned values.

Defined constants are also used for predefined atoms. As describedin “Properties and Atoms” an atom is an integer value identifying aproperty. Atoms are used to avoid passing arbitrary-length propertyname strings back and forth between the client and the server.

Performance Optimizing

While designing, writing, and debugging your application, you can lookfor ways to improve its performance.

Whenever possible, you should use Xlib functions that do not requireprotocol replies. That is, in functions that are called frequently,especially in the event loop, avoid Xlib routines with names containingFetch, Get, or Query. Most of these functionsreturn information from the server, and as such, they are subject tonetwork delays and will slow down your application. Much of thisinformation can be had from events.

In general, keep the feedback loop between the user's action and theprogram's response as short as possible.

ANSI-C and POSIX Portability

The MIT Release 5 X distribution is compliant with ANSI-C and POSIXstandards, and portable across a wide variety of platforms.While the goal of the ANSI-C and POSIX standards is portability,many systems do not implement these standards, or do not implementthem fully, so the MIT R5 distribution defines new header files thatattempt to mask the differences between systems.The header files are<X11/Xfuncproto.h>, <X11/Xfuncs.h>,<X11/Xosdefs.h>, and<X11/Xos.h>.The contents and usage of these header files are described inChapter 15,Other Programming Techniques.None of these files are part of the official R5 standard, sothey may not be shipped with your system. But theycan be very useful in writing portable applications, so wehave included them with the code from this book, which you canget as described in the Preface.

Debugging an X Application

All programmers know that debugging is by far the most difficultand time consuming aspect of programming. This is where you catchall the problems caused during the writing stage and often alsoproblems in the design stage. One can rarely foresee all theissues when designing a program.

There are some techniques that make debugging X applicationseasier. One, of course, is to have good tools. The C programcheckerlint helps find problems such as mismatches in thenumber of arguments to a function, variables declared but not used,or misused pointers. Although it often finds something to complainabout that you do not consider an error, it also provides usefulinformation.

Use of a good debugger such asdbx avoids the need to continuallyplaceprintf statements in the code and recompile.

The standard application xwininfo is good for displaying informationabout a window, including its window ID and name, parent and children IDsand names, all the window attributes, and the window manager hints set forthat window. Use the-all option or see the xwininfo referencepage in Volume Three, for information on printing just the needed information.

The standard application xprop, which displays the name, type,and value of each property set on a window, is useful in debuggingapplications that set or read properties. It can also display fontproperties. This application is also described in Volume Three.

If your application generates protocol errors during debugging,it is easier to locate the error if you turn off Xlib's requestbuffering (described in“Buffering”). This is done withthe XSynchronize() call placed immediately after the callto connect with the sever (XOpenDisplay()).

One of the most common places to have difficulty debugging isin event handling. For this reason, we recommend that allprograms under development containprintf statements atthe beginning of each branch of their event handling, so that theprogrammer can watch the sequence of events in one window and thevisible performance of the application in another. This printstatement can be placed within a compile-time#ifdef DEBUG, #endif pair. Then define thissymbol on the compiling command line. Later, all the printstatements can be taken out of the compiled code by simplychanging the command line when recompiling. Although the eventtypes are coded as numbers and will normally be printed that wayby the printf statements, they are easily translated back intostrings that match their symbols using the technique describedin“Printing the Event Type” in Chapter 8

X applications are difficult to test thoroughly. Here are someof the miscellaneous tests you should put your application through:

  • Be sure to try all combinations of raising and loweringdifferent windows to test the application's response toexposure. Does it redraw unnecessarily?

  • Try all combinations of pressing and releasing differentpointer buttons to see if anything breaks.

  • Try operating the program in a busy network environment.

  • Try the application on a variety of different servers.Does it work on both color and monochrome systems?

  • Try running the application on machines with differentarchitectures and bit and byte orders.

  • What happens when you type function keys or other uniquekeys on a particular keyboard?

  • Is it possible to crash the application by specifying thewrong set of resources or command line arguments?

If your application can pass all these tests, you have done a good job.

Errors

There are really three levels of error handling in programs usingXlib. The first level you implement yourself by monitoring thereturn status of the routines that create server resources. Thisallows the client to modify the arguments of the request and tryagain. The second level, protocol errors, is usually caused by aprogramming error, and the third by a fatal system error such as acrash of the machine running the server or network failure. Thesecond two types are handled by two separate error-handling functionsthat can be set by the client but, by default, simply print a messageand exit the client.

As an example of the first level of error handling, a client shouldalways check to see whether it was successfully connected to thedisplay server withXOpenDisplay() before proceeding. If thisconnection did not succeed, the client should print a message tostderr indicating what happened and which server it attemptedto connect to. This process will be demonstrated in Chapter 3, “Basic Window Program”

X protocol errors occur when routine arguments do not conformto accepted ranges or when IDs do not match existing resources,etc. These types of errors are sent toXErrorHandler.Fatal errors, such as a broken connection with the server, areunrecoverable conditions and invoke theXIOErrorHandler.Both error handlers by default display an intelligible (if notintelligent) message and then exit.

The possible X protocol error messages and their general causesare listed in Appendix B,Error Messages and Protocol Requests, of Volume Two.These error messages also specify which protocol request caused theerror, which you can also look up in Volume Two, Appendix B,Error Messages and Protocol Requeststo determine which Xlib routine may have caused the error. Thismapping is not unique because several Xlib routines often generatethe same protocol request.

User-defined error-handling routines will be called from the errorhandlers if you pass procedure names toXSetIOErrorHandler()orXSetErrorHandler(). If either is passed a NULLfunction pointer, the respective default handler will be reinstated.

If you write your own error-handling routines, it is recommendedthat you use XGetErrorText() or XGetErrorDatabaseText()to get the string describing an error code, so that the codes ofextensions can be handled properly. XGetErrorDatabaseText()uses the resource manager to provide error messages from the fileXErrorDB, located by default in/usr/lib/X11.

Only the error-handling routine XErrorHandler(or the one you define) receives error events.These events cannot be selected or received by windows.

The XErrorEvent Structure

Example 2-2 shows the XErrorEvent structure and itsmembers. The value of each member of this structure is displayedby the default X protocol error handler.

Example 2-2. The XErrorEvent structure

typedef struct _XErrorEvent {    int type;    Display *display;           /* Display the event was read from */    XID resourceid;             /* Resource ID */    unsigned long serial;       /* Serial number of failed request */    unsigned char error_code;   /* Error code of failed request */    unsigned char request_code; /* Major opcode of failed request */    unsigned char minor_code;   /* Minor opcode of failed request */} XErrorEvent;

The following list describes each member of the XErrorEventstructure in detail:

  • The serial member is the number of requests sent over thenetwork connection since it was opened, starting from 1. Thedifference betweenserial and the last request processedas reported in error messages tells you how many requests to countback in order to find the request that caused the error.

  • The request_code is a protocol representation of thename of the protocol request that failed; these are decodedin Appendix B,Error Messages and Protocol Requests, of Volume Two.

  • The error_code is one of the items describedin Volume Two, Appendix B,Error Messages and Protocol Requests, such asBadWindow.

  • The minor_code is zero unless the request is part ofan extension. If it is, theminor_code indicates whichrequest in the extension caused the error.

  • The resource_id indicates one of the server resources(window, colormap, etc.) that was associated with the requestthat caused the error.

Synchronizing Errors

Since error events are not displayed precisely when they occur,it is often informative to look up the protocol request as wellas the error code to determine which function the error occurredin. You cannot rely on the debugger to indicate where the erroroccurred because of Xlib's request buffering and other delays.

It is useful to use XSynchronize() to make sure thatprotocol errors are displayed as soon as they occur. WhenXSynchronize() is invoked, the performance of graphics willbe drastically reduced. The same result occurs by setting theglobal variable _Xdebug to any nonzero value when runninga program under a debugger (UNIX only).

Software Interrupts

Xlib does not handle software interrupts. Therefore, if yourecursively call back into Xlib from a signal handler, theprogram will hang or crash. This is mostly an issue on systemsthat feature threads or multiple processors.The correct way to handle signals is to never make Xlib callsfrom signal handlers.



[4]In this manual, whenever you see typewriter font (such as thatused for the routineXSync()), it means this word would betyped verbatim into C code as a symbol, structure name, structuremember, or Xlib routine. Italic typewriter font is used for dummyarguments to Xlib routines, since they could be typed into code asshown but are arbitrary. The argument names used in this volumeare the same as the names used on the reference pages in Volume Two.

[5]Do read this section even if you are already familiar withwindowing systems, to make sure you understand X's particularimplementation of windowing.



http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_html/ch02.html

0 0