Pango is available for download from www.pango.org (see Resources). At the time of this writing, the current version is Pango 0.14. It is available as source code, as Red Hat-style source RPM (RPMS), and as a binary RPM distribution for Red Hat Linux 7.0. The other packages that are necessary for creating and displaying widgets with internationalized text -- GTK+ 1.3.3 and GLib 1.3.3 -- are also available from the site.
The latest development versions of Pango, GTK+, and GLib are always available from the GNOME CVS (see Resources).
Pango also depends on Dov Grobgeld's FriBidi package. You can use the "mini" version bundled in Pango or download the latest version from the FriBidi project on SourceForge (see Resources).
To build GLib, you'll need the libtiff, libgiff, and libjpeg libraries, the sources of which are also available from the Pango download page.
If you are installing the pre-built GTK+ and GLib RPMs, they are noted as installing in a different set of directories than the stable versions, so you can have both installed at once. If you are compiling the libraries from the source, you can provide a different prefix for where to install the executables and libraries when you configure the compilation. The following example shows the sequence for making and installing Pango, but a similar sequence is used for the other packages.
Configuring, making, and installing in a non-standard location
cd pango-0.14 ./configure --prefix=/usr/local/tkg make make install |
Compiling and installing the distribution is straightforward, particularly on Linux systems that use the RPMSs prepared by Owen Taylor of Red Hat. Follow the instructions on the Pango download page, and build and install the packages in this order: GLib-1.3, FriBidi, Pango, and then GTK+-1.3.
If you do install the packages in a non-standard location, make
sure that you add their bin directory to the front of
your path. For example, I put the following in my .bashrc
file:
Add the Pango and GTK+ bin directory to your path
declare -x PATH=/usr/local/tkg/bin:$PATH |
Compiling programs that use Pango
The example programs are written in C, and there is no real magic in any of the programs. The closest that they come to magic is when the latter two programs use GTK+ to create a window containing a label by using just a few lines of code. Even that, however, is straightforward GTK+ programming that is covered in detail by other developerWorks articles (see Resources).
Possibly the closest that any C program comes to incantations is
in the arguments provided to the compiler and linker so they can find
the right headers and libraries, respectively. Fortunately, GTK+
provides the gtk-config-2.0 program to take the guesswork
out of compiler and linker arguments. (GNOME provides the similar
gnome-config, and Pango has its own
pango-config.)
If you're already familiar with using gtk-config with
GTK+, note that gtk-config-2.0 is the version to use with
the development versions of GTK+ 2.0 (and it's the main reason for
putting the extra bin directory on your path).
gtk-config-2.0 --cflags returns arguments for use when
compiling, and gtk-config-2.0 --libs returns arguments
for use when linking. Instead of just running these programs from the
command line -- instructive as that can be -- you can include the
commands in a Makefile within back-ticks (`) so they are
evaluated as part of evaluating a Makefile variable or rule. For
example, I used the following as my Makefile for these programs:
Sample Makefile using gtk-config-2.0
CC=gcc LDLIBS=`gtk-config-2.0 --libs` CFLAGS=-Wall -g `gtk-config-2.0 --cflags` all: attr-table gtk-label pango-label |
In the previous article, I described Pango's attributes and its rendering pipeline using this example:
<u>car </u><span foreground="blue"><u>is </u>THE CAR</span> in Arabic |
and showed how Pango turned the marked-up text into a string and a Pango attribute list.
The following program, attr-table.c, shows this in
practice. It declares a string str containing the
marked-up text in the previous example, calls pango_parse_markup() to turn the
marked-up text into a string and an attribute list, and then outputs
the markup for an HTML table that shows the attribute values.
attr-table.c
1 /** attr-table.c **/
2 #include <gtk/gtk.h>
3 #include <stdlib.h>
4 #include <string.h>
5 6 int main(int argc, char *argv[])
7 {
8gchar *str = 9"<u>car </u><span foreground=\"blue\"><u>is </u>THE CAR</span> in Arabic"; 10 gchar *text;
11 PangoAttrList *attrs;
12 PangoAttrIterator *iterator;
13 gint start, end;
14 PangoAttribute *attr;
15 16pango_parse_markup (str, -1, 0, &attrs, &text, NULL, NULL); 17 18 g_print("<html>\n<head>\n");
19 g_print("<meta http-equiv=\"Content-Type\""
20 "content=\"text/html; charset=\"UTF-8\">\n");
21 g_print("</head>\n<body bgcolor=\"white\">\n");
22 g_print("<table border=\"1\" bgcolor=\"white\">\n");
23 24 iterator = pango_attr_list_get_iterator(attrs);
25 26 g_print("<tr>\n<td>String:</td>");
27 do {
28 pango_attr_iterator_range(iterator, &start, &end);
29 30 g_print("<td>%.*s</td>", MIN((gint)strlen(text), end - start),
31 &text[start]);
32 }
33 while (pango_attr_iterator_next(iterator));
34 g_print("</tr>\n");
35 36 iterator = pango_attr_list_get_iterator(attrs);
37 38 g_print("<tr>\n<td>Foreground:</td>");
39 do {
40 pango_attr_iterator_range(iterator, &start, &end);
41 if ((attr = pango_attr_iterator_get(iterator,
42 PANGO_ATTR_FOREGROUND))) {
43 const PangoAttrColor *color_attr = (const PangoAttrColor *)attr;
44 g_print ("<td>#%04x%04x%04x</td>", color_attr->red,
45 color_attr->green, color_attr->blue);
46 } else {
47 g_print ("<td>Â </td>");
48 }
49 }
50 while (pango_attr_iterator_next(iterator));
51 g_print("</tr>\n");
52 53 iterator = pango_attr_list_get_iterator(attrs);
54 55 g_print("<tr>\n<td>Underline:</td>");
56 do {
57 pango_attr_iterator_range(iterator, &start, &end);
58 59 attr = pango_attr_iterator_get(iterator, PANGO_ATTR_UNDERLINE);
60 61 if (attr) {
62 g_print ("<td>Yes</td>");
63 } else {
64 g_print ("<td>Â </td>");
65 }
66 }
67 while (pango_attr_iterator_next(iterator));
68 g_print("</tr>\n");
69 70 g_print("</table>\n</body>\n</html>\n");
71 72 pango_attr_iterator_destroy (iterator);
73 74 exit(0);
75 }
|
attr-table.c in detail
2#include <gtk/gtk.h> |
The include statement on line 2 is all that you need to use to tell the compiler to include the dozens of header files associated with GTK+ and, since Pango is incorporated into GTK+, it's also all you need to use Pango-specific functions in your GTK+ program.
str, which contains the marked-up text, is declared in
lines 8 and 9.
16pango_parse_markup (str, -1, 0, &attrs, &text, NULL, NULL); |
Line 16 is where the action is. pango_parse_markup()
converts the marked-up text in str into a text string,
which is left in text, and a Pango attribute list, which
is left in attrs. The remaining arguments aren't used in
the example program. In particular, some useful error checking has
been omitted for the sake of brevity.
Lines 18 to 22 just print the HTML markup for the start of an HTML page containing a table.
24iterator = pango_attr_list_get_iterator(attrs); 25 26 g_print("<tr>\n<td>String:</td>");
27 do {
28pango_attr_iterator_range(iterator, &start, &end); 29 30 g_print("<td>%.*s</td>", MIN((gint)strlen(text), end - start),
31 &text[start]);
32 }
33 while (pango_attr_iterator_next(iterator));
34 g_print("</tr>\n");
|
A single Pango attribute records the start and end of the span of
text to which it applies, but it is easier to layout text by dealing
with spans of text where each span has the same set of attributes.
pango_attr_list_get_iterator() returns a Pango attribute
iterator that is used to step through the spans of text that have
consistent attributes. This allows the code that is using the iterator
to avoid dealing with overlapping attributes. For example, where two
attributes intersect, the attribute iterator finds three spans: one
with the first attribute, another with both the first and second
attributes, and a third span with just the second attribute.
When the attribute iterator is initialized in line 24, it
identifies the first span of text with consistent attributes. The
do-while loop in lines 27 to 33 simply
prints the markup for an HTML table cell containing the portion of
text that is spanned by the current set of Pango
attributes. The pango_attr_iterator_next() in the
while statement advances the iterator to the span of text
with the next style until it returns NULL at the end of
the text.
The MIN macro in the g_print statement in
line 30 is necessary because the value of end for the
last span is equal to G_MAXINT, the maximum integer
value, and is not equal to the length of the string. If you're
unfamiliar with g_print(), it's a robust
equivalent of the standard C function printf() and is
provided by GLib, which is used by GTK+.
The result of lines 24 to 34 is the HTML markup for a table row
where each cell in the row contains the text spanned by each iteration
of iterator.
The attribute iterator is reinitialized in line 36 and is used in lines 39 to 51 to loop through the text spans again. Once again, the loop prints the markup for an HTML table cell: If the span has a foreground color attribute, the cell contains the hexadecimal representation of the color, and if it doesn't, the cell contains a no-break space entity.
Line 43 casts attr to a Pango color attribute so the
print statement can access the extra parts of a
PangoAttrColor that a common or garden
PangoAttribute structure does not have. There is no harm
in treating the color attribute as an ordinary attribute since
the structures for all Pango attributes begin with the same
members.
Lines 53 to 68 are similar to the previous loop, except this time the code inside the loop tests for the current span of text having an underline attribute.
In real life, a program would be likely to test for all 15 Pango attribute types, but this program gets away with testing for only two since the program is tailored for the example.
The result is an HTML table showing the spans of text that have consistent attributes and the attributes for each span:
|
The previous program showed you how Pango transforms markup into a string and an attribute list, and how Pango simplifies access to the attribute list. But laying out text would certainly be a lot of work if you could only deal with Pango attribute iterators and attribute lists.
Fortunately, as part of Pango's integration into GTK+, GTK+ 2.0
understands Pango attribute lists, and you set the attributes of a
label using gtk_label_set_attributes() and a Pango
attribute list.
pango-attr.c, shown below, does just that: It uses
pango_parse_markup() to convert marked-up text to a
string and an attribute list, then it creates a label showing the text
and sets the label's attributes with the attribute list. The program
also creates a window to hold the label and connects two callback
functions to the window so the program exits cleanly when you close
the window.
The previous example used uppercase text to represent right-to-left
text such as Arabic or Hebrew. This convention is used by the Unicode
Standard and UAX #9 when giving examples of bidirectional ordering,
and the FriBidi test program even has an option for treating uppercase
text this way so the program can be tested against the examples in the
Unicode Standard. GTK+, however, doesn't provide the option (nor
should it), so pango-attr.c just uses the Latin letters
"a" to "m" in place of the lowercase text in the previous example, and
uses the first five letters from the Hebrew block in place of the
uppercase text. The Hebrew characters are represented in the program
by XML-style hexadecimal numeric character references, which
pango_parse_markup() understands.
Note that the right-to-left text is a two-letter word followed by a three-letter word instead of the two three-letter words in the previous example. Even if you (like me) don't read Hebrew and don't have the Unicode Standard handy to check which character is which, when you look at the window produced by the program, you'll still be able to see that the two-letter word is to the right of the three-letter word when the text is displayed in a window.
pango-label.c
1 /** pango-label.c **/
2 #include <gtk/gtk.h>
3 #include <stdlib.h>
4 #include <string.h>
5 6 gint eventDelete(GtkWidget *widget, GdkEvent *event,gpointer data)
7 {
8 return(FALSE);
9 }
10 11 gint eventDestroy(GtkWidget *widget, GdkEvent *event,gpointer data)
12 {
13 gtk_main_quit();
14 return(0);
15 }
16 17 18 int main(int argc, char *argv[])
19 {
20 GtkWidget *window;
21 GtkWidget *label;
22gchar *str = "<u>abc </u><span foreground=\"blue\"><u>de </u>" 23"×× ×××</span> fg hijklm"; 24 gchar *text;
25 PangoAttrList *attrs;
26 27 gtk_init(&argc,&argv);
28 29pango_parse_markup (str, -1,0, &attrs, &text, NULL, NULL); 30 31label = gtk_label_new(text); 32gtk_label_set_attributes(GTK_LABEL(label), attrs); 33 34 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
35 gtk_container_add(GTK_CONTAINER(window), label);
36 gtk_window_set_title (GTK_WINDOW (window), "Pango Label");
37 gtk_container_set_border_width(GTK_CONTAINER(window), 30);
38 gtk_widget_show_all(window);
39 40 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
41 GTK_SIGNAL_FUNC(eventDelete), NULL);
42 gtk_signal_connect(GTK_OBJECT(window), "destroy",
43 GTK_SIGNAL_FUNC(eventDestroy), NULL);
44 45 gtk_main();
46 exit(0);
47 }
|
When you compile this program using the development version of GTK+ and then run it, you will see the window on the screen, but you will also get a warning message on your console or terminal warning you against using the development version of GTK+. If you've gotten this far, you know that you are using the development version, so you can safely ignore the message.
The output of the program is a window containing the styled text:
Label styled by Pango

There is an even easier way. Since this article series is about
Pango, I've concentrated on how Pango works, but Pango is so
thoroughly integrated into GTK+ that you can create formatted text in
a label directly from the same marked-up text that you've seen used
with pango_parse_markup().
gtk-label.c, which isn't being shown in its entirety,
is almost identical to pango-label.c, except that this
program uses gtk_label_set_markup() instead of the
combination of pango_parse_markup() and
gtk_label_set_attributes(). The changed lines are shown
below:
Portion of gtk-label.c
27label = gtk_label_new(NULL); 28gtk_label_set_markup(GTK_LABEL(label), str); |
The only other difference between the programs is a changed window title.
The output of the program is a window containing the same styled text:
Label styled by GTK+

This article and the previous article have shown you how to use Pango. In
particular, they've shown you the 15 types of text attributes that
Pango supports and how to specify the text attributes using a simple
markup scheme. The first article describes and this second article
demonstrates how you can use the pango_parse_markup()
function to convert the markup into Pango text attributes. This second
article also shows how you can take advantage of Pango's integration
into GTK+ and use the markup with gtk_label_set_markup()
to directly specify a GTK+ label widget's appearance.
The example in this article shows Pango successfully laying out a mixture of right-to-left and left-to-right text, and the screenshots in the first article show text in multiple languages -- including Arabic, Greek, Hebrew, Japanese, and Russian -- being laid out by Pango. Based on your knowledge of Pango attributes and how to use the markup scheme, you will now be able to do the same with the text in your GTK+ and GNOME programs.
- See the first of this two-part introduction, The Pango connection, Part 1 here on developerWorks.
- Visit Pango.org for Pango information and downloads.
- See Dov Grobgeld's FriBidi library.
- GNOME is included in most Linux distributions and is
also being adopted by several commercial UNIX vendors.
Visit GNOME.org for more information on GNOME.
- See the three-part series on
GNOME programming by George Lebl, here on developerWorks: Part 1, Part 2, and Part 3.
- The Unicode Bidirectional Algorithm is defined in UAX
#9, The Bidirectional Algorithm.
Tony Graham is the author of Unicode: A Primer , the first and currently only book about the Unicode Standard, Version 3.0, and its uses. An Australian, Tony is a Specialist member of the Unicode Consortium. He can be reached at tkg@menteith.com.





