Clutter: a beginner’s tutorial in Japanese (TAKE 1).

Moblin (日本語サイトなんかあったのかぁ) で採用されている UI のフレームワークである Clutter バージョン 1.0 の初心者向け(?)チュートリアルを日本語にしてみた。このチュートリアルは TuxRadar Linux というフリーソフトウェアに関する技術ニュースやチュートリアルなんかを執筆し公開しているウェブサイトのもの。原文はとても「流暢な英語」(口語体でイギリス英語) なので、どうでもよいところ (ウーとかアーとか唸ったり、つまらないジョークだったり) :P は無視した。原文は全体的に読みづらい印象あり。ちなみに Clutter の本家では 0.9 までの古いバージョンのチュートリアルは公開されているけど、1.0 では API も変更されているので、バージョン 1.0 向けはこのチュートリアルが最初かも。
本文の中で説明しているけど、このチュートリアルはあくまでも一時的なもので、現在は Python を使った本格的なチュートリアルを作成中とのこと。
【更新】
一気に読み上げてブログにまとめてしまおうとしたけど、かなりの長文になってしまい、ブログ形式で記述・修正するにはそれなりに手間がかかるため何回かに分割して掲載することにした。まずはアニメーション作成までにする。


Moblin には「いけてる」機能がたくさんありますが、その中でも Clutter がナンバー1の人気でしょう。なぜかですって?
OpenGL のアクセラレーション付きで、オブジェクト指向で、GTK+ に統合された API があなたを納得させられないのであれば、おそらくあなたが今使っているのは強力なアニメーション・フレームワークだとか、簡単にテクスチャを操作でき「電光石火」でオブジェクトを取得できるほど素晴らしいシステムなんでしょうね (という遠回しの皮肉:訳注)。
但し Clutter にも1つ問題があります。それは参考になるドキュメントがホントに少ないということです。Clutter の使い方を学習したいと考えているハッカーは大勢いますが、今すぐ始めるにしてはウェブにも幾分情報が不足しています。私たち編集者はユーザ志向ではないオープンソース・プロジェクトは嫌いなので、最小限の時間で Clutter を習得するしたいと考えている人達のために、チュートリアル的なガイドを数時間を費やして作成してみました。
インテル社はせっかくの素晴らしい技術を手持ちぶたさにしないよう、我々 TuxRadar に寄付してくれるほど親切な企業です。そのため一時的ではありますが、私たちの記事の横に Moblin に関する広告を載せることにしました (原文にあるフラッシュを使った広告のこと)。定期購読者のみに提供している記事をご覧いただいている Linux Format の読者らはモバイル系 Linux に「捧げた」特集記事をご覧いただける予定です。我々 TuxReadar では次回の記事から Python を使った Moblin 向けのプログラミング・チュートリアルの連載を開始する予定です。
ご存じのとおり、Moblin で面白い技術の1つが Clutter であり、インテルのグラフィックス・ライブラリは Moblin や Ubuntu Netbook Remix のユーザインタフェースのようなフロント・エンド部で広く利用されています。Clutter は理解しやすく、使いやすく、加えてまったく面白い技術です。たとえ、まだ試したことが無いという場合でも、ご安心下さい。私たちが Clutter を使ったプログラミングを身につけるための簡単な方法を紹介します。あるいは、Clutter をもっと理解したいのであれば、先ほどの Moblin の広告をクリックしてみて下さい。そこには、ここで紹介したことの他にもいろいろな情報があります。
覚えておいてほしいこととして、あくまでのこの記事は Clutter のドキュメントで今現在不足している箇所を補うための「臨時措置」みたいなものだということです。私たちは、もっと広い視野でみた Python を中心とする Clutter のチュートリアルを作成中ですが、それを完成するには2,3ヶ月必要であるとみています。その間は、ここで紹介するチュートリアルで我慢していただき、Clutter を使ったプログラミングを楽しんで欲しいと考えています。
初めの一歩
私たちはのらりくらりと紹介していくつもりはありません – 詳細な理論の説明は割愛して早速 Clutter を使ってみることにします。まず最初に、Clutter のアプリケーションをビルドするのに必要なものをインストールして下さい – もし Debian/Ubuntu をお使いなら libclutter-1.0.0 と libclutter-1.0-dev、そして当然ながら GCC も必要です。
Clutter を使って作成したウィンドウを「ステージ」(Stage) と呼び、「アクター」(Actor) と呼ばれるいくつかのオブジェクトをそのステージに追加することができます。アクターをステージに追加すると、そのオブジェクトの描画は Clutter が担当します – ステージの上にあるアクターはあちこち自由に移動させたり回転したり、大きさを変更したりなどの命令を出すことができ、それらの処理は全て Clutter がまかなってくれます。
本当に簡単なオブジェクトを題材に Clutter を使ってみることにしましょう。そうすることで、自分の環境で Clutter の開発ができる準備が整っているかどうかを確認することができるでしょう。ここで紹介したコードをコピーして example.c という名前のついたファイルに貼り付けてみて下さい:

#include <clutter/clutter.h>
#include <stdlib.h>
int main(int argc, char *argv[]) { clutter_init(&argc, &argv);
ClutterColor stage_color = { 0, 0, 0, 255 };
ClutterActor *stage = clutter_stage_get_default(); clutter_actor_set_size(stage, 512, 512); clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color); clutter_actor_show(stage);
clutter_main();
return EXIT_SUCCESS; }

そしてコマンドラインから以下を実行します:

$ gcc example.c -o clutterapp `pkg-config clutter-1.0 --cflags --libs`

エラーなくコンパイルが終了したら、コマンドラインから “./clutterapp” と入力してサンプル・プログラムを起動できます。ここで、古いバージョンのディストリビューション (例えば Ubuntu 9.04 など) では Clutter のパッケージもバージョン 1.0 ではなくバージョン 0.9 を使用することになると思いますが、このバージョンはバージョン 1.0 と 100% 互換性は無いので注意して下さい。もしディストリビューションのバージョンをアップグレードして Clutter のバージョン 1.0 を利用する予定がないのであれば、古い方の実装に合わせて関数名と、pkg-gconfig の呼び出しを変更する必要があります (例えば Ubuntu 9.04 ならば clutter-0.9)。
一度でもサンプル・プログラムが動いたのを見てしまうと、それ以上はつまらなく見えてしまうかもしれませんが: “./clutterapp” を起動すると、背景が黒くタイトルバーを持つウィンドウが表示されます。そして、えっと、それだけです。特に記憶に残る程のものではありませんが、実はそれが重要なポイントです。なぜなら、この状態は Clutter の内部で設定が全て適用され、Clutter のアプリケーションとして準備が整った状態を表しているからです。
tut_clutter1.png
(初めて作成した Clutter のアプリケーション – ただ単に黒い背景を持つ大きなウィンドウですが、お使いのシステムが Clutter を使って開発できる環境になったことの証明でもあります。)
それでは、このサンプル・プログラムがやっていることを簡単に説明してみることにします…

  • clutter_init() は Clutter を「作動させる」関数なので、Clutter を使ったプログラムを作成する際はこの関数を呼び出すことになります。この関数に argcargv を引き渡していますが、その理由は Clutter にはコマンドラインのオプションがいくつか用意されており、このように引き渡すことでそれらを指定できるようになっています。そのオプションについては後で説明しますが、ここで知っておくべきことは、この関数に Clutter 専用のオプションを引き渡すと、Clutter は、この argcargv の解析を行って、それが完了した引数は自動的にその変数から削除されるようになっており、これ以降の処理ではそれらの「引数」は参照できなくなるということです。
  • ClutterColor は、1個の色を表す情報 (赤、緑、青、アルファ値) を格納するための構造体にすぎません。色の情報は0〜255の範囲内で指定したり、0x00〜0xff の16進数で指定することができます。
  • ClutterActor は Clutter の中で最も重要なデータ型です。このサンプル・プログラムではデフォルトのステージを取得する目的でこの型を使っています。デフォルトのステージとは clutter_init() 関数を呼び出した時に Clutter が私達のために用意してくれるオブジェクトです。専門用語で説明すると、Clutter のステージは Clutter 専用のデータ型なのですが、私たちの目が届かないところで ClutterActor からキャストされた型でしかなく、プログラムの中で必要に応じてキャストし直すことが可能になっています。
  • clutter_actor_set_size() 関数を使って1個のアクターの大きさを指定します。アクター (ここではステージ) を第1引数として渡してから、横と縦の大きさをそれぞれ第2引数と第3引数で指定しています。
  • clutter_stage_set_color() は、お分かりかと思いますが、ステージの色をセットする関数です。
  • clutter_actor_show() はアクターを表示する関数です。この関数は重要で、これなしでは (このサンプル・プログラムにある) ウィンドウやその他のアクターを表示することができません。
  • clutter_main() は Clutter のメイン・イベント・ループを生成する関数です。この関数を呼び出した時点で、制御が Clutter 側に渡ります。そして何か興味のあるイベントが発生したらその制御を私たち (サンプル・プログラム) に戻してくれます。しかしながら、ご覧のとおり、このサンプル・プログラムでは何も発生しません。これは、あなたがウィンドウを閉じるまで Clutter は何もせずブラブラしている状態であることを意味しています。

以上が Clutter の基本的なプログラムになります – このコードをテンプレートとして利用し、いろいろ追加していくことで新しいプログラムを素早く簡単に作成できるはずです。事実、それが実際にやりたいことでしょう: それでは、これ以降でステージにアクターを追加してみることにします。
Clutter はいろいろな種類 (型) のアクターを提供してくれていますが、ここで使う型は ClutterRectangle と呼ばれているものです。ステージを使った場合と同様に、ClutterRectangle 型を ClutterActor 型にキャストすることができるので、そのように実装してみましょう – 次のコードをサンプル・プログラムで clutter_actor_show() 関数を呼び出している行の直前に挿入してみて下さい:

ClutterColor actor_color = { 0, 255, 0, 128 };
ClutterActor *rect = clutter_rectangle_new_with_color(&actor_color);
clutter_actor_set_size(rect, 100, 100);
clutter_actor_set_position(rect, 100, 100);
clutter_container_add_actor(CLUTTER_CONTAINER(stage), rect);
clutter_actor_show(rect);

このコードは、新たに緑色 (透明度は 50%) をした矩形を生成して、その大きさと位置を指定し、ステージに追加しています。CLUTTER_STAGE() というマクロの使い方に注意して下さい – これはステージという1アクターを ClutterStage 型にキャストする際に使用します。
矩形を生成した後は、それをステージに追加して表示してやることで、あとは Clutter が実際に描画してくれます。
コンパイルした “./clutterapp” を実行すると、今までよりもすこしだけ面白みのあるウィンドウが表示されるでしょう: 1個の四角形が表示されるだけですが!はいはい、分かっています。ちょっと飽きてきましたね。大丈夫です – ここからもっと面白いものにしていきます…
tut_clutter2.png
(Clutter のウィンドウの中には ClutterRectangle 型のアクターが1つ含まれているので、漠然ではありますが面白そうになってきました)
必要に応じて四角形を描画する
ちょっとコードを整理して、もっと簡単に矩形を生成したり大きさを指定できるようにしてみます。では、次のコードをサンプル・プログラムに追加してみて下さい:

ClutterActor *create_rect(ClutterColor col) {
ClutterActor *rect = clutter_rectangle_new_with_color(&col);
clutter_actor_set_size(rect, 256, 128);
clutter_actor_set_position(rect, 128, 128);
clutter_container_add_actor(CLUTTER_CONTAINER(stage), rect);
clutter_actor_show(rect);
return rect; }

この関数は指定した色で四角形を生成し、ステージの特定の位置に配置します。この関数を呼び出す前に “stage” の定義を移動し、プログラム内のどこからでも参照できるようにしておく必要があります。さらに四角形を表すリファレンスもグローバルで宣言しておいて下さい。すなわち、次の2行を #include 文の直後に挿入することになります:

ClutterActor *stage;
ClutterActor *rect1 = NULL;

重要 (という程でもないと思うが…:訳注) ここでは、ヘッダ・ファイルを用意して前もって全ての関数を定義するようなことはしていません。そのため、自分の関数は正しい順番でプログラムのファイルに配置していくようにする必要があります – もし関数Aが関数Bを呼び出す場合、関数Bはファイルの中で関数Aよりも前に記述しておく必要があります。上の create_rect() 関数は main() 関数から呼び出すことになるので、main() よりも前に配置しておいて下さい。これ以降でも、いろいろな関数を定義する予定なので、それらを呼び出す前に、予めプログラムのファイルに挿入しておく必要があるので注意して下さい。
ということで、main() 関数を次にように変更します:

int main(int argc, char *argv[]) {
clutter_init(&argc, &argv);
ClutterColor stage_color = { 0, 0, 0, 255 };
// ローカルではなく、グローバル変数の stage を使う stage = clutter_stage_get_default(); clutter_actor_set_size(stage, 512, 512); clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color);
// 新しく追加した関数を呼び出して四角形を生成する ClutterColor red = { 255, 0, 0, 128 }; rect1 = create_rect(red);
clutter_actor_show(stage);
clutter_main();
return EXIT_SUCCESS; }

ここは、それほど大きな変更ではありませんでした。実際のところ、プログラムをコンパイルして実行してみると前と似たような結果になるのが分かるでしょう。但し、これからは必要に応じて矩形を生成できるようになったので、いろいろな色でいろいろな形の四角形を生成し、それらをアニメーションのように動かしてみます。「アニメーション?」 ええ、そうです。まだそれについては説明していませんが、心配は無用です。とっても簡単です。
Clutter でアニメーションを実現する際は「タイムライン」(Timeline) を使います。そして “ticks” という時間単位で通知される度に、コマ撮りのように画像を更新してアニメーションにします。
それではプログラムを変更して複数の四角形を描画してみましょう。まだアニメーションを実行するためのコードは挿入しません。まず複数個の四角形が正しく描画されることを確認しましょう。プログラムの先頭にある変数の定義を次のように変更して下さい:

#include <clutter/clutter.h>
#include <stdlib.h>
ClutterActor *stage; ClutterActor *rect1 = NULL; ClutterActor *rect2 = NULL; ClutterActor *rect3 = NULL; ClutterActor *rect4 = NULL; ClutterActor *rect5 = NULL; ClutterActor *rect6 = NULL;

それでは、今まで同様に stage 変数を定義し、かつ6つの四角形を表すリファレンスを用意します。これら6つの四角形は create_rect() 関数を使ってそれぞれ別々の色で生成するため、main() 関数を次のように変更します:

int main(int argc, char *argv[]) {
clutter_init(&argc, &argv);
ClutterColor stage_color = { 0, 0, 0, 255 };
stage = clutter_stage_get_default(); clutter_actor_set_size(stage, 512, 512); clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color);
ClutterColor red = { 255, 0, 0, 128 }; ClutterColor green = { 0, 255, 0, 128 }; ClutterColor blue = { 0, 0, 255, 128 }; ClutterColor yellow = { 255, 255, 0, 128 }; ClutterColor cyan = { 0, 255, 255, 128 }; ClutterColor purple = { 255, 0, 255, 128 };
rect1 = create_rect(red); rect2 = create_rect(green); rect3 = create_rect(blue); rect4 = create_rect(yellow); rect5 = create_rect(cyan); rect6 = create_rect(purple); clutter_actor_show(stage);
clutter_main();
return EXIT_SUCCESS; }

次に、このサンプル・プログラムをコンパイルしても6個の四角形は表示されません – 四角形は1個だけしか表示されないのです。これは、なぜなら全ての四角形が同じ場所にあるからです。全てが重ね合わさってしまったというわけです。
ここで面白いことに挑戦してみます: これらの四角形を回転させてみましょう。まず、回転する際の情報を保存するための変数を用意します。次のコードを変数を定義している場所に追加してみて下さい:

gdouble rotation = 0;

それから、タイムラインを生成して有効にします。タイムラインを生成するには clatter_timeline_new() 関数を使い、タイムラインの更新間隔を Clutter に伝えます。この値の単位はミリ秒なので、”1000″ は1秒を表します。タイムラインを生成したら、アニメーションとして画像を更新する際に呼び出す関数に “new-frame” というシグナルを関連づける必要があります。最後にタイムラインをループさせるよう指示し、実際にタイムラインを動かします。
では main() 関数の中で6番目の四角形を生成する create_rect() 関数を呼び出した後に、次のコードを挿入して下さい:

ClutterTimeline *timeline = clutter_timeline_new(60);
g_signal_connect(timeline, "new-frame", G_CALLBACK(on_timeline_new_frame), NULL);
clutter_timeline_set_loop(timeline, TRUE);
clutter_timeline_start(timeline);

on_timeline_new_frame() 関数は、実行の制御が Clutter から戻ってきた時に呼び出されるようになっているので、画像を更新してアニメーションが動いているようにみせることができるのです。この関数は専用の引数を受け取ることになっていますが、ここでは問題ありません – ここで変数を外しても後でコピー&ペーストできますから。
この on_timeline_new_frame() 関数が処理する内容は単純です: “rotation” という変数の値を少しだけ増やし、clutter_actor_set_rotation() 関数を使って四角形の回転角をそれぞれ異なる量だけ変更します。四角形はグローバル変数として全て保持しているので大して難しいことはありません。それでは on_timeline_new_frame() 関数をプログラムに追加してみて下さい:

void on_timeline_new_frame(ClutterTimeline *timeline, gint frame_num, gpointer data) {
rotation += 0.3;
clutter_actor_set_rotation(rect1, CLUTTER_Z_AXIS, rotation * 5, 0, 0, 0); clutter_actor_set_rotation(rect2, CLUTTER_Z_AXIS, rotation * 4, 0, 0, 0); clutter_actor_set_rotation(rect3, CLUTTER_Z_AXIS, rotation * 3, 0, 0, 0); clutter_actor_set_rotation(rect4, CLUTTER_Z_AXIS, rotation * 2, 0, 0, 0); clutter_actor_set_rotation(rect5, CLUTTER_Z_AXIS, rotation, 0, 0, 0); clutter_actor_set_rotation(rect6, CLUTTER_Z_AXIS, rotation * 0.5, 0, 0, 0); }

この時点でプログラムをコンパイルし実行することができます。6つの四角形がその左上を中心に角度を計算しながらそれぞれ回転していくのが分かるでしょう。この先に進む前に、ちょっとだけプログラムを変更することにします。

  1. Clutter は、そのオブジェクトに属しているメモリを自動的に解放してくれるという賢い作りになっていますが、これは通常、ステージに取り付けられているオブジェクトのみが対象です。今回生成したタイムラインはステージには取り付けていないので、そのメモリは使い終わったら手動で解放しなければなりません。そのために、main() 関数の中にある clutter_main() を呼び出した後すぐに次のコードを追加して下さい:
    g_object_unref(timeline);
    
  2. 四角形がその左上隅を中心として回転することは予想外でした。代わりにアクターの中心を基点に回転させればもっと綺麗でしょう。これは、Clutter で「アンカー・ポイント」(Anchor Point) と呼ばれている情報を変更することで実現できます – すなわち、四角形はアンカー・ポイントを中心に回転することになります。create_rect() 関数に次のコードを追加してみて下さい:
    clutter_actor_set_anchor_point(rect, 128, 64);
    

tut_clutter3.png
(透明な四角形が回転しているのがわかりますか? そうだとしたら成功です)
(TAKE2へ続く)