You are on page 1of 6

Chapter 10

Drawing Text

Displaying text is an important function in all computer systems. Prior


to the emergence of graphical user interfaces, text-based interfaces were
the norm, and users interacted with com uters t roug text IS a ter-
mm s. ven now, most users spen their time reaaing and entering tex-
tu in ormation. X provides ample facilities for displaying text. However,
unlike text display terminals, X displays can show text in varying sizes and
~hapes (fonts). This chapter describes how to display text in X, and in~
eludes an example program that illustrates how to handle text output in
X applications.

The size, weight"and style d<i,l;,rmipethe.appea<ance"oU..spec4.fau .


i typefa~!he si:eTs expressed in terms of the height of the glyphs in the
font. Usually, sizesare expressed in points, each point being approximately
1/n-inch. Some common sizes are 10 and 12 points.
..
The style or slant of a font indl,sate;.u.b.t;;eJ.ti&::Y..9r!,lCAtati!?,n,of
ea~h"cha[acte( in thefQtlt. Typical You can use asterisks (*) as wildcard characters for parts of the name that can be arbitrary. For ex-
styles are roman for upright characters and italic for characters tilted to the right. ample, if you want only Adobe's 14-point Helvetica Bold font, you can specifYit with the follow-
ing name:
You can think of a font as an array of glyphs indexed by the character's code. To draw a character,
the X server extracts the bitmap corresponding to that character's code from the font's glyph array
and applies foreground and background colors using the bitmap as a mask. As you will see in the viewfile program shown in Listing 10.1, the capability of usingwildcards in
The character code, on the other hand, depends on the encoding used to represent the characters in a font's name helps yot,!devise a good scheme for handling multiple fonts in an X application.
the .alphabet of a l:mguage. ~~II (J\rn~2~~~,~~::..fo~I.~~!.?~JnterchaI1 el an~ I~2."
Latln-1 (International Standards Orgalllzatlon)-are examPles of commonly used character codes. Font Listing and Examination
1O••_ •.••~~M~~*r;~'· ••·"'.oi'lI..WM~

ont Names ...~.•.


When you prepare a document with any graphical word processor (or desktop publishing software),
ou usual . dicate a s ecific fan b namin its . eface,.size, wei ht, ~.2.d.~ Ie. For example, 14-
point Helvetica Bo refers to a specific font. Starting with XII R3, names of fonts are constructed in
"a slmdar manner. The fa;; nameInClJoeS'iiiformation on the font's desi ner and the eface,weight,
style, and size. There is ot er information as we r, sue as tee aracter set encoding to be use if'
~-
Listing Fonts with xis onts
The first utility, xlsfonts, lists the names of all available fonts. You can run it by typing xlsfonts
~the shelrprorr;p·t~,ryot7·~~nt~o ~;'the'~":r'~'~r;;rr 1f'poi:r Helvetica typefaces in bold weight,
t e ant, intercharacter spacings (monospaced or proportional), and the screen resolution (in pixels for instance, you can do so with the following command:
per inch) at which the font should be used. For instance, you can identifY a 14-point Helvetica
Bold font with the following name (see Chapter 3, "Exploring X Applications," for information on
X11R3 and X11R6 font naming conventions): which generates the following in a typical system:
-adobe-helvetica-bold-o-normal--14-140-75-75-p-82-is08859-1
-adobe-helvetica-bold-r-normal--14-140-75-75-p-82-iS08859-1
-adobe-helvetica-bold-o-normal--20-140-100-100-p-103-is08859-1
-adobe-helvetica-bold-r-normal--14-140-75-75-p-82-is08859-1
Aliliough the name looks complic~ted, it is easy enough for a program to construct it from the parts. -adobe-helvetica-bold-r-normal--20-140-100-100-p-105-is08859-1
Here, adobe refers to Adobe Corporation which donated the font. The typeface is helvetica in
bold weight and regular style (represented by r). The normal refers to normal-sized characters. You C~e?:~j~iled i=~~~,,~ f~,nt?y using th~-~~~~w~,;l.:~~nts .•••

Size information follows the two dashes after normal. The 14 indicates the font's size in pixels, the
140 refers to the size of the font in tenths of a point. The next two numbers (75 -75) indicate the Viewing Fonts with xfd
m
horizontal and vertical screen resolutions for which the font was designed. In this case, the font is You can use the xfd utili to vie a.£o t. To see a specific font, type xfd -fn <fontname> at the
designed for a screen with 75 dpi (dots per inch) resolution. Next comes the spacing information- ";hcir;' ro;;p;.. e <fontname> argument s auld be the name of an arrrr;r1'oIJ.t(WIth wllaGlt s, I
mindicates monospaced font (equal spacing between any two characters), and p denotes propor- necessary. For example, to view Roman 14-point Helvetica Bold font, use this command:

-
tionally spaced font (spacings vary from one letter to another). The name here includes a p because
Helvetica is a proportionally spaced typeface. xfd -fn "*helvetica*bold-r*140*" &

The next number (82) is the average width of the character glyphs in units of ten,t:hsof a pixel. The Figute 10.1 shows the resulting display. Character sizes may be different from 14-point type be-
last part in the font's name is the character encodings used to index into the font. The iso8859-1 cause the font is being displayed on a screen with resolution different from the 75 dpi for which the
refers to the ISO Standard 8859/1 character set, also known as the ISO Latin-1 set. screen is designed.

It the f()r:~ize and.~idthare zero font ~sa scalable o~e; you ~ use a~sUable foAt_!!,taqy..,s,.4e.
Font s;;"tmg capabIlIty and support for s ~ mg fonts was mtroouced in X11R5.

1ll\lQ.4gh-tru:iom n;j.11)..~£0Jll,Rlifl!~d, you do. not !w:.~.!o sl?c.:~ify


full names when specifYing a
~he Xlib functions that accept font names have been designed -;~h~r;i'j;'~~pkre f~
If you have a GC with helvb14 as the font and you unload that font, the X server refrains from
Figure 10.1. , unloading the font until the GC is destroyed.
_l ••••
Uce-llold-l!-lIortoal 14-140-75-7!H'-lI2-ISOlI859-1
BoidRoman Helvetica
font displayed by xfd. ~1!':.~_!'~I-t P••• !
dtarllCter 0M0041[0,65)
width 10J left; 0, ricM 10J _t 11, _t 0 [Font. 13, 3)
r_ 0x0020 [0,32) thru OxOOf'f (0,255>
_left.: 0x0000 [0,0) A font is a set ofbitma s. When writing text output, the X server draws each characrer by painting
,
t e plxe s III a rectang e matching the size of that character's bitmap. Because you have to specify
I
. # $ 'J, & r 1 . + . -
,. I where the server should start drawing the characters, you need to know the size of each character's
0
(9
1
A
2
B
3
C
4
0
S
E
S
F
7
G
B
H
9
I
:
J K
c

L
-
M N
~
?
0
bitmap-at the very least, the maximum size of a character's bitmap in a font. )(jib includes func-
P Q R S T U V W X Y Z \ tions that enable you to obtain such information.
· a b c d e f Q h I I k I m n 0

..
I) Q r s t u v w x v z ' { }
"

. -
·
I
±
C

£
• ". Y
u ,
II
,C' •
I c


~
'J.
-
'.10 •
..,. )

A A A A A A IE C E E E E I
Font helvb14; /* A valid font ID */
a N 0 0 0 0 0 x iii U U U U V I> B
• •
II ft
I
6
I
6
I
6
I
6
II!
II
C
+
t 6
il
e
ii
!
0
I'
0
I
v
T
b
T
0
XFontStruct *info_helvb14; /* Pointer to returned 1nfo */

" info_helvb14
,--------------
~ XQueryFont(p_disp, helvb14)j

When you call XQueryFollt, )(jib allocates an XFontStruct structure, fills it with information re-
Font Loading and Unloading trieved from the X server, and returns a pointer. Save the pointer for subsequent use, and when you
no longer need the font, call XFreeFont to.unload the font and, at the same time, free the memory
allocated by)(jib for the XFontStructure structure.
Rather than calling XLoadFont followed by XQueryFont, you can call the ~LoadQueryFont func-
tion to load a font and get the font information with a single request to the server. Like XQueryFont,
XLoadQueryFont returns a pointer to an XFontStruct structure. Use the following:
Display *p_disp; /* Identifies the connection to the X server */
char fontnamel] "*helvetica-bold-r*140*"; 1* Font name */ Display *p_disp;
Font helvb14; /* Font 10 */ char fontname[) = "*helvetica-bold-r*140*";
XFontStruct *info_helvb14;

if((helvb14 = LoadFont(p_disp, fontname)


{ if((info_helvb14 ~ XLoadQueryFont(p_disp, fontname») ~~ NULL)
fprintf (stderr, "Cannot load font:, %s\n"', fontname); {
exit (1); fprintf(stderr, "Cannot load font: %s\n", fontname);
exit(l) ;

where the pfogram exits if the font cannot be loaded. (XLoadFont returns a 0 when it fails.),When
successful, you can start using the 14-point bold Helvetica font, shown in the example, by setting The XFontStruct structure that contains aggregate information about a font is defined in <X11/
the font attribute of a GC. To do this, call XSetFont: Xlib. h> as follows:
typedef struct
..•XSetFont(p_disp, thisGC, helvb14); {
XExtData *ext data; /* Room for future expansion */
Subsequently, when any text is drawn with this GC, the output will be in 14-point bold Helvetica Font fid; /* Font ID for this font */
font. rrsigned direction; /* One of: FontLeftToRight or*/
/* FontRightToLeft */
Because fonts are erver-resident resourcCl!whellYour aJ?plication no longer needs a font, you should unsigned min_char_or_byte2;/* First defined character */
e e t e ont with the XUnloadFont cion. This function call has the following form: unsigned max_char_or_byte2;/* Last defined character */
unsigned min_bytel,; /* First row that exists */
unsigned max_bY tel ; /* Last row that exists */
1* True = all characters have*1 typedef struct
/* nonzero size *1 {
1* Character to print for *1 short lbearing; 1* Distance to left edge of bitmap */
1* undefined character *1 short rbearing; /* Distance to right edge of bitmap *1
n_properties; 1* Total number of properties*/ short width; 1* Distance to next char's origin *1
int
XFontProp *properties; 1* Pointer to array of */ short ascent; 1* Baseline to top edge of bitmap */
1* additional properties *1 short descent; 1* Baseline to bottom edge of bitmap *1
1* Info on smallest character*1 unsigned short attributes; 1* Other font·specific info *1
1* Info on largest character *1 XCharStruct;
1* Info on all characters */
To understand the meaning of the fields in this structure, refer to Figure 10.2 where the informa-
1* Pixels above baseline */
1* Pixels below baseline *1 tion is shown for two different characters. I
} X
You can safely ignore some of the members of the XFontStruct structure. An important member
is f id which is the font ID. The direction flag may be important if your application handles lan- t:t#Output
guages that expect characters to go from right to left rather than left to right.

The ascent and descent members are the number of pixels that the font extends above and below
a baseline (see Figure 10.2). You can use these values to decide how far apart you position lines of
text.

Figure 10.2. Each function draws a number of characters on a sir.ll;le line. The fi~J functions draw all the
Font size infOrmation in
XFontStruct and
XCharStructBOUn;ding box of e\aCh glyph
c aracters USing t e ont speC! Ie ..T.t :i~
G9 ~hich you." rovide,as an a£guml!nt. They are called in
for"h"
'- t e same wex;
XCharStruct structures.
____ .~..;;;.;.~_I
*_••.••
s~t£_j.Q.g ~.i.?QJ,ey~ */
1 * Nymber o~r. c.te,J;§ M.l s rjJJJJ.~

-tDrawString(p_diSP, window~ thisGC, x, y: string, nchars);


,XDrawImageS ring p_~, 1ndo, lS~C, X, y, str~ng, ncnars);
You specify a starting position-that
.
is, where the server places the origin of the first character's
bitmap (see Figure 10.2). Then it copies the foreground pixel value (from the GC) to all pixels cor-
responding to 1s in the bitmap. XDrawSt ring does not alter the pixels if the bitmap is 0.
XDrawlmageSt ring, on the other hand, also fills the pixels corresponding to 0s in each character's
Origin
of each
bitmap with the GC's background color. Figure 10.3 shows the appearance of strings displayed with
glyph these two functions. In this case, the window's background is white, and the GC's foreground and
background are black and light gray, respectively. As you can see, XDrawlmageString fills in the
background of each character's bounding rectangle.

Figure 10.3.
Text output from
XDrawString and
XDrawlmageString.

The per_char in the XFontStruct structure is an array of XCharSt ruct structures that contain Multiple Fonts on the Same Line
further information on each character in the font. This structure is defined in <X11 / Xlib. h> as the
If ou want to use more than oneJont on the same line of text, use the XDrawText function. This
folIowing:
function acce ts t e In ormation a out t e string segments tn an X f eXt Item structure, wli.lclI is
defined in <X11 /Xlib. h> as the following: - ~
liner1 J .chars = "lets you";
char *chars; 1* Pointer to the string to be drawn *1 line[1J:nchars = strlen("lets you");
int nchars; 1* Number of characters in string *1 line[1] .delta = p_helv014·>max_bounds.width/2;
int delta; 1* Distance from last char of prevo string */ linel1 J .font = p_helv014·>fid;
Font font; 1* Font to be used (None means use GC's font) *1
XTextItem; line[2].chars = "mix fonts on a line.";
line!2) .nchars = strlen("mix fonts on a line.");
Each XTextItem structure contains information about one chunk of text. The first two members line[2] .delta = p_ncsb14·>max_bounds.width/2;
identify the string and its length. The member named delta is an offset in pixels that is applied line[2] .font = p_ncsb14·>fid;
before drawing this string. The last member in the XCharSt ruct structure, font, specifies the font
1* In the event processing loop ...*1
to be used when drawing this string. When calling XDrawText, you provide the usual Display pointer, if(theEvent.xany.window == Main &&
Drawable, and GC: theEvent.type == Expose &&
theEvent.xexpose.count == 0)
text_chunks[]; 1* Array of strings to be displayed
numchunks; 1* Number of XTextltem structures XClearWindow(p_disp, Main);
XDrawText(p_disp, Main, theGC, 30, 30, line, 3);

window, thisGC, x, y, text_chunks, numchunks);

Additionally, you provide the strings in an array ofXTe xt I t em structures, the n umber of such struc-
tures, and the coordinates (x, y) (with respect to the origin of the drawable) where the first charac- Figure 10.4.
ter of the first string is displayed. Mixing/OlliS on the same
line with XDrawText.
DrawText dis lays each strin using the font s ecified in the font field of the XTextItf;lm struc-
t~t oes this by loading the font Into t e GC that you provi e In the function can. If the :font As you can see, once the XTextItem structures are ready, displaying them is easy-just
call XDrawText.
field in the XTextItem is set to None, XDrawText uses whatever font the GC happens to have. In a real application (for example, a word processing program), you allocate the XTextltem struc-
tures dynamically and initialize them as the user types in text and selects a font.
Figure 10.4 shows a sample output generated with XDrawText. Here are the relevant lines of code
that produce the output:
Display *p_disp;
Window Main;
XTextItem line[3] ; en drawing text, you have to decide where to osition the string. Unlik~ a text display terminal,
XFontStruct *p_ncsb14, *p_courb14, *p_helv014; t e server oes not automatically handle carriage returns or ine eeds. You have to position each
char n_ncsb14[] "*new century schoolbook-medium-r*140*"
n_courb14[] line of text explicitly and draw it by calling one of these functions: XDrawSt ring, XDrawText, or
"*courier-bold-r*140*", ,
n_helv014[] "*helvetica-medium-O*140*"; XDrawlmageString. To help you position each line, Xlib provides the functions XTextWidth and
XTextExtents that compute the dimensions (in pixels) of a text string when it is displayed in a
specified font. When calling these functions, you have to provide a pointer to an XFontStruct struc-
e that contains iatermatibn'aboutth'7font. Thus, you have to use XLoadQueryFont-(S>f XLoadFont

if ((p_ncsb14 = XLoadQueryFont(p_disp, followed by XQueryFont) before calling XTextWi t ana XTextExtents.


n_ncsb14)) == NULL)
exit(1) ;
if (p_courb14 XLoadQueryFont(p_disp, n_courb14))
exit (1);
NULL) String Width Computation
if ((p_helv014 XLoadQueryFont(p_disp, n_helv014) ) NULL) J
exit (1); XTextWidth is the simpler of the two dimension-computing functions. It accepts a pointer to the
array of characters and returns the width of a string in pixels:
line [0].chars = "XDrawText"·
linel0].nchars = strlen( "XD~awText")' XFontStruct *p_font; 1* Structure with info on font *1
line[0] .delta = p_courb14->max_bound~.width/2; char text[ 1 = 'Hello";
l1ne[0] .font = p_courb14->fid; int text_width;
You can use this width for horizontal placement of text. For vertical spacing, use the sum of the
ascent and descent fields of the XFontStruct structure pointed by p_font.

The XTextExtents function provides more information about the area occupied by il text string
when displayed in a particular font. This function returns the information by filling in an
XCharStruct whose address you provide as an argument. The calling syntax is the following:
XFontStruct *p_font; /*
char text[] = 'Hello';
int direction, /* Font direction returned here */
ascent, /* Font's ascent returned here */
descent; /* Font's descent returned here */
text_sizes; /* Sizes returned in this struct *f

XTextExtents(p_font, text, strlen(text),


&direction, &ascent, &descent, &text_sizes);

You can interpret the information returned in the variables ascent and descent, and the
XCharStruct structure text_sizes, by consulting Figure 10.2. The figure illustrates the informa-
tion in an XCharStruct structtlre for individual characters; remember that the fields of the
text_sizes structure pertain to the entire string.

The server is not involved when you call XTextWidth or XTextExtents to compute the sizes of text
being displayed. The XFontStruct structure specified in the function calls has all the information
needed by the functions to perform the calculations. Thus, you pay no significant penalty if you
make frequent calls to these functions.

File Viewing: A Sample Program


Now that you have an idea about the fonts, text positioning, and text output functions, this section
provides a complete example that consolidates these concepts with some ideas (copying areas) from
the last chapter.

The application is a program named viewfile that enables you to view the contents of a file in a
font of your choice. For example, you can view the file viewf ile. c by typing the following com-
mand at the shell prompt:

When started this way, viewfile first opens and reads the contents of the file. Then it displays the
first part of the file in a window under a menubar.