目次


Pango の接続

第 2 回

Pango の実際

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: Pango の接続

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:Pango の接続

このシリーズの続きに乞うご期待。

Pango の入手

Pango は www.pango.org からダウンロードして入手することができます (参考文献を参照)。この記事を書いている時点では、現行バージョンは Pango 0.14 です。これはソース・コード、Red Hat スタイルのソース RPM (RPMS)、および Red Hat Linux 7.0 のバイナリーRPM 配布版として入手できます。国際化テキストでウィジェットを作成して表示するために必要なその他のパッケージ GTK+ 1.3.3 と GLib 1.3.3 も、このサイトから入手できます。

最新の開発バージョンの Pango、GTK+、および GLib は、GNOME CVS (参考文献を参照) からいつでも入手することができます。

Pango は Dov Grobgeld の FriBidi パッケージにも依存関係があります。Pango にバンドルされている「ミニ」バージョンを使うか、あるいは SourceForge の FriBidi プロジェクト (参考文献を参照) から最新バージョンをダウンロードしてください。

GLib をビルドするには、libtiff、libgiff、および libjpeg ライブラリーが必要になります。これらのソースも Pango のダウンロードのページから入手できます。

事前にビルド済みの GTK+ と GLib の RPM をインストールする場合、これらは安定バージョンとは別のディレクトリーのセットにインストールするので注意してください。この場合、両方を同時にインストールできることになります。ソースのライブラリーをコンパイルする場合は、コンパイルを構成するときに、実行可能プログラムとライブラリーをインストールする場所として、異なる接頭部(prefix)を指定することができます。次の例は Pango の作成とインストールのシーケンスを示すものですが、他のパッケージの場合でも同様のシーケンスで行います。

標準の場所以外への構成、作成、およびインストール

cd pango-0.14./configure --prefix=/usr/local/tkgmakemake install

配布版のコンパイルとインストールは簡単です。Red Hat の Owen Taylor が提供する RPMS を使用する Linux システムでは特にそうです。Pango のダウンロードのページにある指示に従って、GLib-1.3、FriBidi、Pango、そして GTK+-1.3 の順序でパッケージをビルドしてインストールしてください。

パッケージを標準以外の場所にインストールする場合は、パスの先頭にbin ディレクトリーを必ず追加してください。たとえば私の場合、.bashrc ファイルに次のような行を含めています。

パスに Pango と GTK+ のbin ディレクトリーを追加する

declare -x PATH=/usr/local/tkg/bin:$PATH

Pango を使用するプログラムのコンパイル
ここでのプログラムの各例は C で書かれていて、これらのプログラムのどこにも魔法は仕掛けられていません。これらのプログラムで最も魔法になるようなものとして最も近いのは、終わりの 2 つのプログラムで GTK+ を使って、単に数行のコードで、ラベルを含むウィンドウを作成しているところです。しかし、それさえも、別の developerWorks の記事 (参考文献を参照) で詳細に取り上げられている、GTK+ の簡単なプログラミングなのです。

ひょっとすると、あらゆる C プログラムで最も呪文に近いのは、コンパイラーとリンカーに指定する引数に見つかるかもしれません。コンパイラーとリンカーがそれぞれ正しいヘッダーとライブラリーを見つけることができるのですから。幸い GTK+ には、コンパイラーとリンカーの引数を推察するgtk-config-2.0 プログラムがあります。(GNOME には同様のgnome-config があり、Pango には独自のpango-config があります。)

GTK+ でgtk-config を使う方法をすでによくご存知なら、gtk-config-2.0 が、開発バージョンの GTK+ 2.0 と一緒に使うバージョンだという点に注意してください (パスに特別にbin ディレクトリーを書き込むのは、それが主な理由です)。

gtk-config-2.0 --cflags はコンパイル時に使用する引数を戻し、gtk-config-2.0 --libs はリンク時に使用する引数を戻します。これらのプログラムを単にコマンド行から実行する代わりに(もちろんそれで役に立つ場合があるのですが)、コマンドをバッククォート (`) で囲んで Makefile に組み込むことができます。この場合のコマンドは、Makefile の変数や規則の評価の一部として評価されます。たとえば私の場合、これらのプログラム用に、自分用の Makefile として次のものを使用しました。

gtk-config-2.0 を使った Makefile のサンプル

CC=gcc
LDLIBS=`gtk-config-2.0 --libs`
CFLAGS=-Wall -g `gtk-config-2.0 --cflags`
all:	attr-table gtk-label pango-label

Pango 属性の処理

前回の記事では次の例を使って Pango の属性とそのレンダリングのパイプラインについて説明しました。

<u>car </u><span foreground="blue"><u>is </u>THE CAR</span> in Arabic

そしてこのマークアップされたテキストが Pango で、どのようにストリングと Pango 属性リストに変わるかを説明しました。

次に示すプログラムattr-table.c はこれを実際に行うものです。ここでは、前の例のマークアップされたテキストを含むストリングstr を宣言して、これをストリングと属性リストに変えるためにpango_parse_markup() を呼び出し、次に属性値を示す HTML テーブルにマークアップを出力します。

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   {
  8	gchar *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
 16	pango_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>&nbsp;</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>&nbsp;</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 の詳細
2 #include <gtk/gtk.h>

行 2 の include ステートメントですが、GTK+ に関連した多数のヘッダー・ファイルを組み込むようにコンパイラーに指示するために使う必要があるのはこれだけです。また、Pango は GTK+ に取り込まれているため、GTK+ プログラムで Pango 固有の関数を使うために必要なのもこれだけです。

マークアップされたテキストを含んでいるstr が、行 8 と 9 で宣言されます。

 16 pango_parse_markup (str, -1, 0, &attrs, &text, NULL, NULL);

行 16 が処理を行うところです。pango_parse_markup() によって、str のマークアップされたテキストが、テキスト・ストリング (text に置かれる) と、Pango 属性リスト (attrs に置かれる) に変換されます。他の引数は、このプログラムの例では使用していません。特に、簡潔にするために、有用なエラー検査は省略しています。

行 18 から 22 で、テーブルを含む HTML ページの開始に、始まりとなる HTML マークアップを出力します。

 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");

単一の Pango 属性で、それが適用されるテキストのスパンの開始と終了を記録しますが、各スパンが同じ属性セットを持つようなテキストのスパンを処理してテキストをレイアウトすると簡単になります。pango_attr_list_get_iterator() は、Pango 属性イテレーターを戻します。これは整合した属性を持つテキストのスパンを列挙するのに使用します。これにより、イテレーターを使用するコードが、重複している属性を処理するのを避けることができます。たとえば 2 つの属性が共通部分をもつところでは、属性イテレーターは次の 3 つのスパンを検索します。1 番目の属性を持つもの、1 番目と 2 番目の両方の属性を持つもの、そして 2 番目の属性だけ持つものです。

属性イテレーターが行 24 で初期化されると、それにより、整合した属性を持つテキストの最初のスパンが識別されます。行 27 から 28 にかけてのdo-while ループで、Pango 属性の現行セットでスパンされたtext の部分とともに、HTML テーブルのセルにマークアップを単純に出力します。while 文の中のpango_attr_iterator_next() は、イテレーターを、テキストの末尾のNULL が戻されるまで、次のスタイルのテキストのスパンに進めます。

行 30 のg_print 文にあるMIN マクロが必要なのは、最終スパンのend の値が最大整数値G_MAXINT に等しくて、ストリングの長さに等しくないためです。g_print() をよくご存知でない方のために説明すると、これは、C の標準関数printf() の頑健なものといえるでしょう。これは GLib に用意されており、GTK+ で使用します。

行 24 から 34 の結果はテーブルの行の HTML マークアップになります。そして行の各セルには、イテレーター の反復ごとにスパンされたテキストが入ります。

属性イテレーターは行 36 で再初期化されて、行 39 から 51 でテキスト・スパンを再度ループするのに使用されます。このループで再び HTML テーブルのセルにマークアップが出力されます。スパンが前景色属性を持っていた場合、セルにはその色を表す 16 進数が入り、そうでない場合は非 BREAK のスペース実体(nbsp)がセルに入ります。

行 43 でattr を Pango カラー属性にキャストするので、出力文は、ごくありふれたPangoAttribute 構造体にはない、PangoAttrColor の特別な部分にアクセスすることができます。カラー属性を普通の属性として扱っても差し支えありません。すべての Pango 属性の構造体は、同じメンバーから始まるためです。

行 53 から 68 はその前のループに似ていますが、ここではそのループ内のコードで、下線属性を持つテキストの現行スパンをテストします。

実際のプログラムでは 15 種類の Pango 属性をすべてテストするでしょうが、このプログラムは例であるため、2 つだけのテストにしています。

この結果は、整合した属性を持つテキストのスパンと、スパンごとの属性を示す、次のような HTML テーブルになります。

ストリングcarisTHE CARin Arabic
前景色:#00000000ffff#00000000ffff
下線:YesYes

Pango を使ったラベル

前記のプログラムでは、Pango でマークアップをストリングと属性リストに変換する方法と、Pango で属性リストへのアクセスを単純化する方法を示しました。しかし、Pango 属性のイテレーターと属性リストだけしか扱えなかったら、テキストのレイアウトは確かに大変な作業になります。

幸い Pango の GTK+ への組み込みによって、GTK+ 2.0 では Pango 属性を認識でき、またgtk_label_set_attributes() と Pango 属性リストを使ってラベルの属性を設定することができます。

以下に示すpango-attr.c では、まさにそれを行います。pango_parse_markup() を使って、マークアップされたテキストをストリングと属性リストに変換します。次にテキストを示すラベルを作成し、属性リストでラベルの属性を設定します。このプログラムはラベルを表示するウィンドウも作成し、そのウィンドウをクローズしたときにこのプログラムがクリーンに終了できるように、2 つのコールバック関数をそのウィンドウへ接続します。

前記の例では、アラビア語やヘブライ語のように右から左に読み進むテキストを、大文字のテキストを使って表しました。この規則は、Unicode Standard と UAX #9 で双方向(bi-directional)テキストのサンプルを示す際に使用されています。また、FriBidi のテスト・プログラムにも、Unicode 標準のサンプルに対してプログラムをテストできるように、このような大文字のテキストを扱うオプションがあります。しかし GTK+ にはそのオプションがない (また、あるべきでもない) ため、pango-attr.c では、前の例の小文字のテキストの代わりにラテン文字 "a" から "m" を使用し、大文字のテキストの代わりにヘブライ語ブロックの最初の 5 文字を使用します。ヘブライ語の文字は、プログラムでは、XML スタイルの 16 進数字文字参照で表されますが、これはpango_parse_markup() で認識できます。

ここでの右から左に読み進むテキストでは、前の例のように 3 文字の語が 2 つではなく、2 文字の語が 1 つの後に 3 文字の語が 1 つ続いていることに注意してください。このプログラムで作成されたウィンドウを見て、たとえば (私のように) ヘブライ語を読めなくて、Unicode 標準が手元にないのでどの文字がどれなのか調べられないときでも、ウィンドウにそのテキストが表示されると、2 文字の語が 3 文字の語の右にあることは見分けられるでしょう。

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;
 22	gchar *str = "<u>abc </u><span foreground=\"blue\"><u>de </u>"
 23	"&#x5d0;&#x5d1; &#x5d2;&#x5d3;&#x5d4;</span> fg hijklm";
 24     gchar *text;
 25     PangoAttrList *attrs;
 26
 27     gtk_init(&argc,&argv);
 28
 29	pango_parse_markup (str, -1,0, &attrs, &text, NULL, NULL);
 30
 31	label = gtk_label_new(text);
 32	gtk_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   }

このプログラムを開発バージョンの GTK+ を使ってコンパイルして実行すると画面にウィンドウが表示されますが、コンソールや端末に警告メッセージも表示され、開発バージョンの GTK+ を使用していることに対して警告が出されます。このプログラムを実行するところまでたどり着けたなら、開発バージョンを使っていることはよくお分かりでしょうから、このメッセージを無視してかまいません。

このプログラムの出力は、スタイル設定されたテキストを含む、次のようなウィンドウです。

Pango でスタイル設定されたラベル
Pango でスタイル設定されたラベル

GTK+ だけで

もっと簡単な方法もあります。この連載記事は Pango に関するものなので、これまで Pango の動作に集中して説明してきましたが、Pango は完全に GTK+ に組み込まれているので、ラベルの中のフォーマットされたテキストを、pango_parse_markup() で使用して見てきた同じマークアップされたテキストから直接作成することができます。

gtk-label.c は、その全体は説明しませんが、ほとんどpango-label.c と同じです。違う点は、このプログラムでは、pango_parse_markup()gtk_label_set_attributes() の組み合わせの代わりに、gtk_label_set_markup() を使うという点です。変更がある行を次に示します。

gtk-label.c の部分
 27 label = gtk_label_new(NULL);
 28 gtk_label_set_markup(GTK_LABEL(label), str);

これらのプログラムの間で他に唯一違うのは、ウィンドウ・タイトルが変わることです。

このプログラムの出力は、同じスタイルに設定されたテキストを含む、次のようなウィンドウです。

GTK+ でスタイル設定されたラベル
GTK+ でスタイル設定されたラベル

サマリー

この記事と「前回の記事」で、Pango の使い方を説明してきました。特に Pango がサポートする 15 種類のテキスト属性と、単純なマークアップ・スキームを使ってテキスト属性を指定する方法を紹介してきました。第 1 回の記事でpango_parse_markup() 関数を使ってマークアップを Pango テキスト属性に変換する方法を説明し、この第 2 回の記事でそれを実際に例で示しています。この第 2 回の記事では、Pango が GTK+ 組み込まれたことを利用して、gtk_label_set_markup() でマークアップを使って、GTK+ ラベル・ウィジェットの表示を直接指定する方法も紹介しています。

右から左に読み進むテキストと、左から右に読み進むテキストが混在しているものを、Pango でうまくレイアウトできることをこの記事の中の例で示しています。また、Pango でレイアウトした複数言語 (アラビア語、ギリシャ語、ヘブライ語、日本語、およびロシア語を含む) のテキストを、第 1 回の記事の中の画面ショットで紹介しています。Pango 属性とマークアップ・スキームの使い方を理解すれば、あなたの GTK+ プログラムや GNOME プログラムのテキストにも同じことができるようになるでしょう。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology, Linux, Open source
ArticleID=231481
ArticleTitle=Pango の接続: 第 2 回
publish-date=04012001