目次


GNOMEnclature

アプリケーションのプログラミングを簡単にする GNOME ライブラリー:第1回

必要なものはすべてそろっています

Comments

コンテンツシリーズ

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

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

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

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

GNOME とは何ですか

GNOME とは、多種多様なものの集まりです。つまり、GNOME とは UNIX 用のグラフィカル環境であり、便利で小規模なアプリケーションやユーティリティーを集めたものであり、そしてアプリケーション・プログラミング・ライブラリーのセットなのです。現在、私たちは、GNOME ライブラリーに専念しています。GNOME ライブラリーにより、開発者は、GNOMEに準拠した一貫性のある強力な GUI アプリケーションをすばやく、しかも最小限の労力で作成することができます。

GNOME ライブラリーを使うのはなぜですか

他のライブラリーを使わずに、GTK+、Motif、Qt などの GUI ツールキットを使用して直接プログラムを作成しないのはなぜでしょう。これらのツールにはそれぞれ利点がありますが、GNOME ライブラリーを利用する利点の方がそれらよりも勝っていると思うからです。GNOME ライブラリーを利用すると、コードやウィジェットの大部分がすでに記述されていたり作成されているために、大幅に時間を 節約することができます。また、これらのウィジェットは、GNOMEライブラリーを使用するアプリケーションのすべてで外観や使い方 (look and feel) が統一されています。さらに、アプリケーション間でコードが共用されているために、アプリケーションごとにコードが メモリー内にロードされるのではなく、共用ライブラリーの一部となり、その結果使用するメモリーの量が少なくなります。しかし、GNOME の最大の利点は、ライブラリーを使用することにより、アプリケーションの機能そのものに専念できる点です。つまり、ユーザー・インターフェースの作成やデバッグに時間を費やす必要がなくなるのです。

GNOME アプリケーションの作成

ここまでの説明で、GNOME を使う意味を理解できたでしょう。では、基礎から説明します。GNOME アプリケーションは、いくつかのライブラリーの 階層 を、最上位レベルにあるGNOME ライブラリー と 一緒に使用します。GNOME ライブラリーは、ヘルパー・ルーチンやクラス、専用ウィジェット(高速、フリッカーなしの高水準描画ウィジェットである GnomeCanvas など) を備え、アプリケーションにフレームワークを提供します。

階層の 2 番目に高いレベルはGTK で、これは GTK+ ライブラリーの一部です。このライブラリーは、GUI アプリケ ーションの作成に使う基本ツールキットやウィジェット (ボタン、ラベル、入力ボックスなど) を提供します。GUI の多くは GTK を使用して直接作成されます。GTKも、GNOME ライブラリーで使用される高度なオブジェクト・システムを提供します。

GNOME アプリケーションの基本構造
GNOME アプリケーションの基本構造
GNOME アプリケーションの基本構造

ライブラリー階層での次のレベルはGDK で、X ライブラリーを包む薄いラッパーです。これを使用するのは、特殊な描画を行う必要があり、ウィンドウに専用のプロパティーを設定しなければならないときだけです。

最下位のレベルはGLib で、C 用のユーティリティー・ライブラリーです。ここには、移植性のあるユーティリティー関数が含まれており、そのほかにもいくつかのコンテナー・クラス (リンク・リスト、サイズ変更可能な配列、可変長ストリング、ハッシュ、イベント・ループ、その他の便利なもの) が含まれています。

ユーザーが GNOME アプリケーションの開発に使用できる言語が C だけの場合でも、アプリケーションをすべて C 言語で作成する必要はありません。実際、GTK+ と GNOME は C で記述されていましたが、Objective C、C++、Perl、Guile、Python、Eiffel など他の言語への結び付けを記述することは簡単でした。

GNOME と GTK+ の層

GNOME ライブラリーは、libgnome、libgnomeui、libgnorba の 3 つの基本部分に分かれています。libgnome は、ユーティリティー・ライブラリーで、狙いは GLib に似ており、GLib の機能に似て、構成情報のロードや保存、アプリケーションの起動、MIME型の識別、メタデータ記憶域などのサービスを行います。libgnomeuiの部分はユーザー・インターフェースの部分で、アプリケーション・フレームワーク (GnomeApp)やキャンバス (GnomeCanvas)をはじめとする、たくさんの便利な専用ウィジェットが含まれています。最後のlibgnorba 部分は、GTK+/GNOME アプリケーションと CORBA技術との統合に使用されます。

GNOME アプリケーションをプログラミングする際には、GTK+ の使い方を知っていることが重要です。libgnomeuiクラスはすべて GTK+ を基にしているため、使い方は標準の GTK+ ウィジェットのものに似ています。

GTK+ は、コンテナー・ベースのツールキットです。そのため、ほとんどのウィジェットは、他のウィジェットを含む「コンテナー」として機能します。たとえば、ボタンは、ほとんどがラベル・ウィジェットを含むコンテナーです。しかし、他のコンテナーは、ウィジェットをまとめるためだけのものでしかありません(これらの中でもっとも便利なのは、いくつかのウィジェットを一列に配置する水平ボックスと垂直ボックス、またはフォーマットやレイアウトに使えるテーブルです)。

この階層を利用すると、すべての形状寸法はすぐに計算されるため、アプリケーションをさまざまな表示上の設定値 (フォント・サイズなど)で実行することができます。ウィンドウのサイズを変更したとき(または、プログラムを国際化対応にしたとき) も正しくそれに対応します。また、実行中に自動生成される GUI の開発も簡単になります。

GTK+ アプリケーションでのウィジェットの階層例
GTK+ アプリケーションでのウィジェットの階層例
GTK+ アプリケーションでのウィジェットの階層例

アクションをあるイベント (ボタンのクリックなど) に接続する必要があるときは、「シグナル 」を使用しなければなりません。これは、特殊な GTK+ クラス・メソッドで、アクションを カスタム関数にバインドすることができます。たとえば、ボタンは「クリックされる」シグナルを持ち、このシグナルには、ユーザーがこのボタンをクリックしたら起こるようにするアクションをバインドすることができます。シグナルはそれぞれ異なります。ハンドラー関数を定義するときは、必ず、正しい関数のプロトタイプを使用してください。

GNOME アプリケーションの例

次に、GNOME アプリケーションの例を見てみましょう。これは、必修の「Hello World」プログラムですが、ただの「Hello World」プログラムではありません。メニュー、「about」 ダイアログ、ステータス・バーがそろって います。

このアプリケーションは、切り離しメニューのドッキング・メニュー・バーとメニュー・ヒントが付いたステータス・バーを備えています。メニューのユーザ定義アクセラレーターをオートセーブして (マウスをメニューに合わせて、目的のキーの組み合わせをクリックします。これで大丈夫です)、標準の 「about」ボックスを備え、標準メニュー項目の自動変換を行います("LANG=es_ES ./hello_world" を実行してみてください。アプリケーションのメニューがスペイン語で表示されます。)

hello_world.c プログラムの画面
hello_world.c プログラムの画面
hello_world.c プログラムの画面

hello_world.c のソース・コード

hello_world.c
1       /* Hello World (Gnome Edition)
2        * Listing 1
3        * This code is public domain, so use it as you please.
4        */
5                               
6       /* this include will include everything needed for GNOME, including all the
7        * libraries that gnome needs, such as gtk, imlib, etc ...*/
8       #include <gnome.h>
9                               
10      /* this is usually defined by autoconf but we're just using simple makefiles */
11      #define VERSION "1.0"
12                              
13      /* "callback" function (signal handler) which will quit the application*/
14      static void
15      exit_hello(GtkWidget *widget, gpointer data)
16      {
17              gtk_main_quit ();
18      }
19                              
20      /* callback function for when the window closes */
21      static int                      
22      delete_event(GtkWidget *widget, gpointer data)
23      {
24              gtk_main_quit ();
25              return FALSE; /* false means continue with closing the window */
26      }
27                              
28      /* a callback for the about menu item, it will display a simple "About"
29       * dialog box standard to all gnome applications
30       */
31      static void
32      about_hello(GtkWidget *widget, gpointer data)
33      {
34              GtkWidget *box;
35              const char *authors[] = {
36                      James Bond,
37                      NULL
38              };
39                              
40              box = gnome_about_new(/*title: */ "Hello World (Gnome Edition)",
41                                    /*version: */VERSION,
42                                    /*copyright: */ "(C) 1999 Secret Agents Inc.",
43                                    /*authors: */authors,
44                                    /*other comments: */
45                                    "An extremely complicated application which "
46                                    "does absolutely nothing useful",
47                                    NULL);
48              gtk_widget_show(box);
49      }
50                              
51      /* define the menus here */
52                              
53      static GnomeUIInfo file_menu [] = {
54              /* some item which is not one of the standard ones, the null
55               * would be the callback, however we don't want to really do anything */
56              GNOMEUIINFO_ITEM_NONE("Something","Just an item which does nothing",NULL),
57              /* standard exit item */
58              GNOMEUIINFO_MENU_EXIT_ITEM(exit_hello,NULL),
59              GNOMEUIINFO_END
60      };
61                              
62      static GnomeUIInfo help_menu [] = {
63              /* load the helpfiles for this application if available */
64              GNOMEUIINFO_HELP("hello_world"),
65              /* the standard about item */
66              GNOMEUIINFO_MENU_ABOUT_ITEM(about_hello,NULL),
67              GNOMEUIINFO_END
68      };
69                              
70      /* define the main menubar */
71      static GnomeUIInfo main_menu [] = {
72              GNOMEUIINFO_MENU_FILE_TREE(file_menu),
73              GNOMEUIINFO_MENU_HELP_TREE(help_menu),
74              GNOMEUIINFO_END
75      };
76                              
77      /* Our main function */
78      int
79      main(int argc, char *argv[])
80      {
81              GtkWidget *app; /* pointer to our main window */
82              GtkWidget *w; /* pointer to some widget */
83                              
84              /* initialize gnome */
85              gnome_init("hello_world", VERSION, argc, argv);
86                              
87              /* create main window */
88              app = gnome_app_new("hello_world", "Hello World (Gnome Edition)");
89              /* connect "delete_event" (happens when the window is closed */
90              gtk_signal_connect(GTK_OBJECT(app), "delete_event",
91                                 GTK_SIGNAL_FUNC(delete_event),
92                                 NULL);
93                              
94              /* add the menus to the main window */
95              gnome_app_create_menus(GNOME_APP(app), main_menu);
96                              
97              /* setup appbar (bottom of window bar for status, menu hints and
98               * progress display) */
99              w = gnome_appbar_new(FALSE, TRUE, GNOME_PREFERENCES_USER);
100             gnome_app_set_statusbar(GNOME_APP(app), w);
101                             
102             /* make menu hints display on the appbar */
103             gnome_app_install_menu_hints(GNOME_APP(app), main_menu);
104                             
105             /* set up some bogus window contents */
106             w = gtk_label_new("Some really really really random\ntext\ngoes\nhere!");
107                             
108             /* add those contents to the window */
109             gnome_app_set_contents(GNOME_APP(app), w);
110                             
111             /* show all the widgets on the main window and the window itself */
112             gtk_widget_show_all(app);
113                             
114             /* run the main loop */
115             gtk_main();
116                             
117             return 0;
118     }

それでは、「Hello World」を詳しく見ていきましょう。プログラムの一部はそのままで内容がわかります。その他の部分にはプログラマーのコメントが付いているので、基本部分に重点を置きます。リスティングの冒頭では、gnome.hをインクルードして、GNOME の全機能の実現に必要な他のライブラリーをすべてインクルードしています。

メイン関数は、次のコードです。

84              /* initialize gnome */
85              gnome_init("hello_world", VERSION, argc, argv);

上の行は、GNOME のライブラリーのすべて、GTK+、その他必要なライブラリーのすべてを初期化します。次に、デフォルトのコマンド行引き数を構文解析します。この初期化の行は、どの GNOME アプリケーションにも必ず記述されていなければなりません。

続いて、次のコードがあります。

87              /* create main window */
88              app = gnome_app_new("hello_world", "Hello World (Gnome Edition)");
89              /* connect "delete_event" (happens when the window is closed */
90              gtk_signal_connect(GTK_OBJECT(app), "delete_event",
91                                 GTK_SIGNAL_FUNC(delete_event),
92                                 NULL);

このセグメントでは、2 つのことを行います。最初の行では、「Hello World (Gnome Edition)」というタイトルが付いた「hello_world」用の新しいアプリケーション (メイン) ウィンドウを作成し、新しく作成したこのオブジェクトを示す「app」を設定します。次の部分の gtk_signal_connect は、オブジェクト「app」にある特定のシグナル ("delete_event") が出されたときに呼び出される関数に、このアプリケーションを接続します。このシグナルは、ユーザーがウィンドウ・マネージャーからこのウィンドウをクローズするように要求したときに出されます。ここで呼び出す関数は、次のようになります。

20      /* callback function for when the window closes */
21      static int
22      delete_event(GtkWidget *widget, gpointer data)
23      {
24              gtk_main_quit ();
25              return FALSE; /* false means continue with closing the window */
26      }

上の関数は、GTK+ にメイン・ループ (gtk_main_quit) を終了し、FALSEを返すように命じています。これは、GTK+ がウィンドウのクローズを続行しなければならないことを示します。それぞれのシグナルには、独自のプロトタイプ (戻り値の意味や引き数のリストもさまざまです) があることに注意してください。たとえば、メニュー項目からのコールバックは、"void function(GtkWidget *, gpointer data)" のようになるはずです。使用できるシグナルとその正しいプロトタイプについては、GTK+ と GNOME の参照マニュアルをご覧ください(参考資料 を参照)。

次に、メニューの定義方法について説明しましょう。GNOME アプリケーション・フレームワーク (GnomeApp クラス) を使って構造を定義します。このフレームワークでメニューを作成し、必要なシグナルをバインドします。メニューとは、メニューを作成する正確な情報を使って事前に設定する静的な構造の配列です。これを簡単に行うために、メニュー定義の単一エントリーを定義できるヘルパー・マクロ (libgnomeui/gnome-app-helper.h に定義されている)が用意されています。次に、「hello_world」の例のメニュー定義を示します(ここでは見やすくするためにコメントを省いています)。

53      static GnomeUIInfo file_menu [] = {
54              /* some item which is not one of the standard ones, the null
55               * would be the callback, however we don't want to really do anything */
56              GNOMEUIINFO_ITEM_NONE("Something","Just an item which does nothing",NULL),
57              /* standard exit item */
58              GNOMEUIINFO_MENU_EXIT_ITEM(exit_hello,NULL),
59              GNOMEUIINFO_END
60      };
61                              
62      static GnomeUIInfo help_menu [] = {
63              /* load the helpfiles for this application if available */
64              GNOMEUIINFO_HELP("hello_world"),
65              /* the standard about item */
66              GNOMEUIINFO_MENU_ABOUT_ITEM(about_hello,NULL),
67              GNOMEUIINFO_END
68      };
69                              
70      /* define the main menubar */
71      static GnomeUIInfo main_menu [] = {
72              GNOMEUIINFO_MENU_FILE_TREE(file_menu),
73              GNOMEUIINFO_MENU_HELP_TREE(help_menu),
74              GNOMEUIINFO_END
75      };

最初の配列は 「File」 メニューを定義しています (スタイル・ガイドによって要求され、必ず「Exit」という項目があります)。このメニューには、タイトルが 「Something」 という独自のカスタム項目が 1 つと、「Just an item which does nothing」 というヒントがあります。ただし、この項目は NULL コールバックを備えているので、クリックしても何も行いません。もちろん、「File」 メニューにも標準の「Exit」項目があり、クリックされると exit_hello 関数 (データ引き数が NULL) を呼び出します。ヘルプ・メニューは、同じように定義されていますが、HTML ヘルプ・ファイルを実際に作成してインストールするときは、先頭の項目を標準のヘルプ・トピックスまで拡張できる点が異なります。main_menu は、メニュー・バーを定義します。これには、2つの (標準) ツリーがあります。メニューの定義が終ったら、gnome_app_create_menus(GNOME_APP(app), main_menu) を呼び出す必要があります。それによって、メニュー・バーが作成され、ウィンドウに貼り付けられます。

また、「appbar」 (ウィンドウ下部にある、飾の付いたステータス・バー) を作成して、そのメニュー項目にヒント (長い説明)をインストールします。これを行うのが、次のコードです。

98               * progress display) */
99              w = gnome_appbar_new(FALSE, TRUE, GNOME_PREFERENCES_USER);
100             gnome_app_set_statusbar(GNOME_APP(app), w);
101                             
102             /* make menu hints display on the appbar */
103             gnome_app_install_menu_hints(GNOME_APP(app), main_menu);

この例で、最後に行う重要なことは、ウィンドウにコンテンツを追加することです。これは、実例にすぎないため、適当にテキストで簡単な GtkLabel を作成し、次のコードを使って追加します。

105             /* set up some bogus window contents */
106             w = gtk_label_new("Some really really really random\ntext\ngoes\nhere!");               
107                             
108             /* add those contents to the window */
109             gnome_app_set_contents(GNOME_APP(app), w);

次に、このアプリケーション・ウィンドウ (および含まれているウィジェットのすべて) を表示し、メイン・ループ関数 (gtk_main) へジャンプして、そこで何かが起きるのを待ちます。これを行うのが次のコードです。

111             /* show all the widgets on the main window and the window itself */
112             gtk_widget_show_all(app);
113                             
114             /* run the main loop */
115             gtk_main();

GNOME アプリケーションの基礎について詳しく説明しました。もちろん、ライブラリーを使って もっと多くのことを実行できますが、これについては、あとから説明します。

GNOME アプリケーションのコンパイル

簡単な GNOME アプリケーションの書き方について学んだので、次に、そのコンパイルについて説明します。アプリケーションのコンパイル用のコマンド行を正しくセットアップできるようにする専用のスクリプト gnome-config が設計されています。gnome-config は、スイッチ (コンパイラーのフラグを取得する「--cflags」またはリンカーの引き数を与える「--libs」) を必要とします。さらに、使用するライブラリー (「gnome」、「gnomeui」など) も指定しなければなりません。それでは、hello_world.c などの簡単なアプリケーションを記述してみましょう。次の囲みは、アプリケーションを正しくコンパイルする簡単な Makefile です。

  CFLAGS=-g -Wall `gnome-config --cflags gnome gnomeui`
  LDFLAGS=`gnome-config --libs gnome gnomeui`
  all: hello_world
  clean:
    rm -f hello_world core

最後の行の「rm」の前にある空きは、TAB 1 つ分で、スペースではありません。引用符は、シングル・バッククォーテーションです。

作成する magic の残りはそのままにしておいてください。もちろん、複雑なアプリケーションには、もっと高度なセットアップが必要になりますが、それは GNOME に関わる問題ではありません。実は、複雑な部分はすべて ユーザーに見えないようにする gIDE というプロジェクトがすでに進行しています。

GNOME プログラミングのその他の利点

GNOME ライブラリーを使用すると、開発者は、他にも次のような利点を得ることができます。たとえば、キャンバス・ウィジェットによって、グラフィックスの表示という高度な手段が提供され、グラフィクス・アプリケーション以外でもそれを使用することができます。たとえば、Gnumeric スプレッドシート、そのグリッドにキャンバス・ウィジェットを使っています。GNOME アプリケーションはセッション・マネージャーと一緒に実行させなければなりませんが、ライブラリーではこれに対して、かなりのサポートを提供しています。マルチドキュメント・インターフェース (MDI) のアプリケーションを作成するフレームワークは、データ・ファイルを含むほとんどのアプリケーションに便利なものですが、単一ドキュメントのアプリケーションに比べて少し複雑になります。しかし、GNOME の MDI フレームワークでは、できる限りこれを簡単にしています。データとユーザー・インターフェースを別々にしていると、単一ドキュメントのアプリケーションを MDI に変換する際の問題を防ぐことができます。

GNOME プログラミングには、ほかに、CORBA を使用しているという特徴があります。GNOME は orb (アプリケーション間の通信を処理するモジュール) として ORBit を使います。CORBA は、ある場所ではすでに幅広く使われていますが、一般的には使われていません。最新のドキュメント・モデルである nobo が開発されている途中ですが、GNOME ワークショップのオフィス・プロジェクトのアプリケーションなどでは、Bonobo を使う予定でいます。Bonobo を使用すると、アプリケーションのモジュラー化がこれまでより大幅に進歩し、アプリケーション間での協調動作が今よりずっと広範囲で実施されるようになります。

開発ツール

GNOME プログラマーの作業に便利ないくつかのツールが開発されています。ここで述べるものはまだ開発途中のものですが、すでに使用することができ ます (ただし、バージョン 1.0 になるまで、重要なプロジェクトにこれらのツールを使わないでください)。

その 1 つは、Glade というインターフェース・ビルダーです。ソース・コードを作成するだけでなく、構築環境全体も作成してくれます。将来は、IDE と統合されて、必要なものがすべてそろった開発ツールになるはずです。

動作中の Glade インターフェース・ビルダー
動作中の Glade インターフェース・ビルダー
動作中の Glade インターフェース・ビルダー

もう 1 つの 「ツール」 であるlibglade は、厳密にはプログラムではありません。Glade から記述ファイルを取り込み、アプリケーションの開始点にインターフェースを作成するライブラリーです。これは、Glade のコードを生成する際に便利な 1 つの方法です。Libglade を使用することによってインターフェースの定義や変更での柔軟性が増します。

3つ目のツールgIDE は、まだ特定のエディターを持たない人に、IDE のサービスを提供します。このツールも Glade に統合されて、市販品に匹敵する開発環境を提供します。


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


関連トピック


コメント

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=290481
ArticleTitle=GNOMEnclature: アプリケーションのプログラミングを簡単にする GNOME ライブラリー:第1回
publish-date=09011999