|
Learning Carbon Foo's Edition Foo: few01@mac.com 1. マルチメディアプログラムの開発環境、もしくはFooの開発環境遍歴 Mac OS Xでプログラミングをすることにした。開発目標はマルチメディアを扱うソフトウェアだ。マルチメディアソフトといってもDirectorやFlashでつくるような紙芝居ではなく、ビデオ映像を処理するソフトウェアで、計算能力を要する。それまではsgiのIRIXというOS上で開発をしてきた。IRIXのマルチメディア開発環境はさすがだ。SGIマシンが10万円なら爆発的に広がっただろう。PCの性能が上がってきたので、PCでの開発に移行したいと思い、Windows, Linux, Macを考えて、それぞれでやってみている。WindowsはWindows 2000、LinuxはVineを使っている。 先行してLinuxで開発してみた。なんとか開発はできた。ImageLibやVideo4Linuxなど優れたライブラリのおかげだ。ただしマルチメディアソフトウェアの開発環境としてはドライバが揃っておらず、開発例も少ないため、相当に面倒であった。それにノートPCで動かしたいと思ったのだが、ノートPCだと映像や音声の入力環境(IEEE1394ドライバなど)が揃っていないという問題がある。またインタフェースは基本的にX Windowを使うことになるのだが、この開発効率と操作性が良くない。WindowsやMacに比べると現状でかなり遅れていると言わざるを得ない。 Windowsでの開発も、Windows 2000を搭載した速いマシンを調達して開始した。ただこれは同僚がすでに別にはじめているので、そのノウハウがたまってからでも良かろうと思っている。開発資料を数冊読んで、チュートリアルにそって、いくつか作ってみたが、相当に複雑だ。ただ開発したソフトウェアが至る所で動くようになるというのは魅力的なので外せないと思う。 MacではOS 9以前に何度か開発をしたが、その不安定さから、私には、どうしても大規模なソフトウェアを作ることができなかった。開発中のプログラムというのは、たびたび不具合で終了するのだが、その度に再起動するのでターンアラウンドタイムが長く、うんざりした。また開発用のドキュメントも少なく、英語のInside Macintoshを読み解きながらコーディングをした。 ところがMac OS Xになって安定さに関しては全く別ものになった。またそれまでCodeWarrier, MPW, MacApp, Think Cなど様々に使ってきたが、それらを上回る素晴らしい開発環境が「ただ」で付属している。ドキュメントに関しても、Webを介して大量にアクセスできる。またiBook(Late 2001)を購入し、いつでもどこでも開発できる環境が整った。もちろんマルチメディアの扱いに関してはQuickTimeという世界最強のライブラリがある。IEEE 1394も標準でついており文句無しだ。これは作るしか無い。 2. Mac OS X上の開発環境の違い Mac OS X上の開発はいろいろな方法で行える。REALbasicのライセンスも持っており、簡単なアプリケーションを作るならこれがベストだ。なにしろあっという間に形になる。しかしREALbasicは、大量のデータを扱うのを苦手とする。大量の文字データやビデオ映像を扱わせると一気に動きが悪くなる。 Project Builderを使う場合に、大きくわけてCocoa, Carbonの2種類の開発スタイルがある(もちろんBSD UNIXで作ったり, X Windowを走らせることもできるが一般的ではない)。Project BuilderとはMac OS Xに付属の開発用ソフトである。統合環境とも言われる。プログラムを作るには、いろいろなファイルを作ってそれらを組み合わせる必要があるが、Project Builderでは、この必要なファイルを管理し、コンパイルし、リンクし、といった作業を一つのソフトでできるようになっている。Visual C++のようなものだ。 Cocoaは、Objective-CもしくはJavaというプログラミング言語を使って開発するものだ。Project BuilderにはObjective-CとJavaのコンパイラが用意されている。Cocoaのもう一つの特徴は、Interface Builderというアプリケーションでインタフェースを容易に設計できることだ。CarbonでもInterface Builderは使えるが、Cocoaほど至れり尽くせりではない。 歴史的にはCocoaはNextStepの開発環境を移植したものであり、APIについているNSという頭文字はNextStepのことである。NextStepについてはここでは述べない(DiscoveringOPENSTEP-J.pdfを参照)。Cocoaだと、Interface Builderで単にインタフェースの見た目が作れるのではなくて、プログラミングの相当な部分もできてしまう。クラスを定義したり、インタフェース要素(ボタンやテキストフィールドなど)の関連がグラフィカルに定義できる。例えば、ボタンを押すとそれに応じて計算値を表示する場合には、計算するクラスを作って(アイコンで表示される)、ボタンからグリグリっと線を引っ張ってきてつないでやる。また計算処理のアイコンからマウスでまた線をグリグリっとひっぱってテキストフィールドにつなげば良い。 またCocoaで使える開発用ライブラリは、それまでのMac OSのライブラリとはがらりと違う。一般にCocoaを使って開発をすると、Carbonを使うよりも何倍も効率的だと言われる。それはこのライブラリ群と、InterfaceBuilderの使い勝手によるものだ。ただし、Objective-CもしくはJavaを使う必要があり、新しいライブラリ群を使いこなさなければならない、という敷き居がある。私の場合はそれまで作ってきたプログラムが主にC++だったので、なんとかそのノウハウを生かしたい、また古いMac OSのライブラリ群にもある程度、知識があったので、それを生かしたいということを考え、Cocoaでの開発は後回しとした。 しかし「Cocoaはやっぱり」などを読みながらCocoaコーディングをしてみると、その開発の容易さにはかなり魅力を感じる。C++にはない生っ粋のオブジェクト指向プログラミングの香りがあり、ここで扱うCarbonにはないシンプルさ、ある意味、美しさと呼べるスタイルが貫かれている。またJavaが使えるというのも魅力的だ。Javaで色々なインタフェースを作ってきたが、現状でユーザインタフェースを作るのに最も有効なプログラミング言語だと思っている。しかしJavaの実行環境は速くなってきたとはいえ、マシンの性能をぎりぎりまで引き出すというレベルには達していない。これまでもインタフェースはJavaで作りながらも、データ処理プログラムはC++で書いてきた。 一方、今回選択したCarbonは、開発環境としては同じくProject BuilderとInterface Builderを使うことができる(もちろんInterface Builderは使わなくてもコーディングできる)。Carbonは、従来からのMac OS開発者が容易に新しいOS X環境に移行できるようにという目的で用意された開発環境である。 そのため、従来からMac OSに存在するライブラリの多くが、そのままCarbonでは使える。またプログラミング言語もC, C++である。したがってProject BuilderにはC , C++のコンパイラが用意されている。Project Builderでは、CodeWarrierなどと同様に、プログラミング言語に関係なく同じ操作でコンパイル、リンクなどの開発作業ができる。 3. Carbon関連資料 さて、Carbonで作ることにしたのはいいのだが、このCarbonの全体像がまったく見えなかった。書いている今もちゃんと見えているとは言い難いが。Event Handlerはどうなっているのか?リソースの扱いは?QuickDrawとQuartzの関係は?QuickTimeはどう使うの?Interface Builderは何をしてくれるのか? もう何もかもわからない、という状況だ。Appleの開発者用ドキュメントリストを見るとCarbon関連の膨大な資料。またAPIだけで、サンプルがなかったり、何をするのかも書かれていなかったり、まるで深い森に入って迷っているかのようだった。 3.1 ありそうでなさそうなサンプルソース 私は、はじめて扱う開発環境では、類似の目的のサンプルソースをとにかく集める所からはじめていた。サンプルソースを解読する過程で、解説書やAPIリファレンスをひも解いて理解を深めると、だんだんと自分がやりたい事ができるようになってくる。IRIX, Linux, Windowsいずれも開発母体や熱心な開発者たちが大量のソースを公開してくれている。これなくして一から自分で作っていたのでは"Hello World!"から抜けるのに相当な習熟期間が必要だろう。 ありがたいことにMac OS X用にはAppleのデベロッパサイトに多数のサンプルソースが置かれている。しかしこれが曲者だった。多くはOS 9以前のものであり、またOS Xに対応していてもCocoaだったり、Code Warrier用だったり、Carbonであっても古いAPIを多量に使ったものだったりするのだ。(ただし慣れてくるとCode Warrier用や、Interface Builderを使っていないサンプルも変換できるようになってくる)それもダウンロードしてみないとわからない。せめてCarbonなのか、Cocoaなのか、Project Builder用なのか、Interface Builderを使っているのか、などのプロフィールをメモしておいてくれれば良いのに。そのため私は生鮮食品の賞味期限を調べるように、サンプルソースの登録された日が2001年後半のものを探した。 またOS Xのデベロッパーツールをインストールすると、多量のサンプルプログラムも一緒にインストールされる。GLUTのサンプルなど素晴らしい。しかしCarbonのサンプルソースは主に"AppearanceSample"と"SimpleText"の2種のみである。ちなみにTextEditもSketchもみなCocoaで開発されている。 ところでCocoaなのかCarbonなのかを区別する方法だが、Cocoaの場合はソースプログラムが".m"と拡張子がmになっている。Carbonは当然".c"である。なぜmなのかはしらないが、ダウンロードして解凍してみてmがついているとがっかりした。 3.2 「Converter: Creating a User Interface with Interface Builder」 Converter: Creating a User Interface with Interface Builder(pdf) ADCのサイトに置かれている、「Converter: Creating a User Interface with Interface Builder」というPDFファイルを読みながら作ると、とりあえずボタンとフィールドを使った簡単なアプリケーション(摂氏を華氏に変換するダイアログ)が作れるようになる。イベントハンドラーの扱い方の第一歩が踏み出せる。最初にやってみたのがこのチュートリアルだ。ただし内容は次の入門Carbonでカバーされているし、英語なので入門Carbonを持っている人にはいらないだろう。 3.3 「入門Carbon」 つい最近のことだが「入門Carbon」(O'Reilly Japan)という本を購入した。日本語で書かれた唯一のCarbon関連書籍だと思う。これは英語の"Learning Carbon"を翻訳したものである。内容は、簡単なダイアログ型アプリケーションを作る過程を通じて、Carbonでのプログラミングについて解説したものになっている。作れるアプリケーション(月旅行プランニングソフト)自体はたいしたことないのだが、導入部の文章や、解説の随所にCarbonでの開発をする上で知らないではすまないことが書かれている。私の場合、相当に苦労してから、この本を読んだので、「あぁ、そういう意味だったのか!」と目から鱗が落ちるような経験をいくつもした。これからCarbonプログラミングをする人には必須だろう。 ただし私が目的としているような面倒なプログラムを作るには、ここに解説されている内容では、あまりに不十分だ。特にマルチメディアデータの扱いと、画面への自由な描画に関して全く触れられていない。
3.4 「小池邦人のプログラミング日記」「Macプロ裏ミング日記」 とりあえず画面に自由に描いてみたいと思ったのだが、「入門Carbon」を読んでも、サンプルコードを探しても、ちっともわからない。まず何を使って描けば良いのかすらわからないのだ。そんな中に見つかったMacWIREの連載記事が「小池邦人のプログラミング日記」だ。特に8回に渡って連載された「Quartz 2D (Core Graphics)を使う」は、どこにも書かれていないことがちゃんと書かれていて大変参考になった。部分的なサンプルソースしか記載されていないが、色々なことがわかった。こういう先達がいてくれて本当にありがたいと思う。 その後、小池氏の開発日記は、以下のサイトに、もっとたくさん古くからあることがわかった。 ここには以降で解説したCarbon Event ManagerやNibベースのCarbonプログラミングに関して詳細に解説されている。しかし実のところ、いま読むと内容がわかるが、はじめの頃にこれを読んでもさっぱりわからなかっただろう。従来のMac OSプログラミングに十分に習熟した人を前提に書かれている。 4. Carbonプログラミングの第一歩 4.1 プロジェクト作成 さて、本章から実際の開発に入る。まずは「入門Carbon」と重複する内容からはじめる。最も単純なアプリケーションはProject BuilderとInterface Builderで作成する。入り口はProject Builderだ。 Project Builderは/Developer/Applicationsの下にある。ダブルクリックして起動する。 ファイルメニューから新規プロジェクトを選ぶ。今回はApplicationのCarbon Application (Nib Based)を選ぶ。Nib BasedというのはInterface Builderを使うタイプのプロジェクトだ。main.nibというファイルが自動生成される。このmain.nibというのがInterface Builderで扱うファイルである。nibのibはInterface Builderの頭文字だ、とは書かれていたが、nが何をあらわすのかはどこにも書かれていない。New Interface Builderだろうか?Next Interface Builderだろうか? (Nib Based)のついていないCarbon Applicationを選ぶこともできる。こっちはmain.rが自動生成される。こっちはベタのテキストファイルである。Interface Builder用のファイルではない。 さて、Carbon Application (Nib Based)を選ぶと、次にプロジェクト名を入れるダイアログが出てくる。作りたいプログラムの名前を入れるのがいいだろう。保存場所はデフォルトでは~/、つまりホームの下だ。好きな場所に変更して良い。 「完了」ボタンを押すと自動的に作られてプロジェクト画面になる。左のグラフィカルなメニューの三角ボタンを押して、どういうファイルが作られたのか見てみよう。 Sourcesには"main.c"だけがある。コメントをはずすと20行ぐらいの最小プログラムである。ResoucesにはInforPlist.stringsとmain.nibがある。InforPlist.stringsには、このプログラムの名前なんかの基本情報がテキスト記述されている。Resourcesの下のExternal FrameworksやProductsは後で触れる。ここはとりあえずmain.nibのさいころみたいなアイコンをダブルクリックしてみよう。 4.2 Interface Builderを触ってみる Project Builderでmain.nibをダブルクリックすると自動的に立ち上がるのがInterface Builderだ。そのAqua全開の美しい見てくれにはうっとりする。四つのウィンドウが表示される。Windowという大きなウィンドウ、main.nib - MenuBarというメニューバー、main.nibというアイコンの並んだウィンドウ、それとCarbon Controlsというツールボックスである。実は一番大事なインスペクタというウィンドウが開いていないのだが、ま、それは置いておいて。main.nibにはすでに自動的に作られたインタフェース要素がアイコン表示されている。MenuBarというのがメニューで、MainWindowというのがメインのウィンドウ、そのままだ。 さてせっかく開いたのだから少し遊ぼう。Carbon Controlsという所から、ボタンとかスライダーとか好き勝手にWindowにドラッグアンドドロップしてみよう。好きに配置したらセーブする。簡単にインタフェースの見てくれができる。
4.3 Buildする Project Builderに戻って、プログラムをBuildしてみよう。Buildとはソースプログラムをコンパイルして、ライブラリやリソースをリンクして、アプリケーションにする操作だ。UnixだとMakeに相当する。Buildは左上のとんかちアイコンをクリックすればできる。左から三番目のとんかちの上にパソコンの画面が重なったアイコンをクリックすると、Buildした上に、アプリケーションを実行してくれる。今回はこっちをクリックしてみよう。 しばらくコンパイルに時間がかかる(main.cをコンパイル中とか、Linkingとか出て、最後にビルドは問題なく完了しました、になる)。そして勝手にアプリケーションが起動する。さっき適当に配置したボタンなどが、ちゃんと反映されているのがわかるだろう。 ただおかれているのではなくて、一応すべて動作する。ただ、ボタンを押しても、それに相当するプログラムが書かれていないので、何も起こらないが。 アプリケーションを終了すると、Project Builderに戻る。アプリケーションを強制的にとめるには、Project Builderで、さっき押したアイコンの所の赤い停止ボタンを押せば良い。 4.4 main.cの中身 main.cの中身を一行づつ解説してみよう。私にも何から何までわかっているとは言えないが、わかる範囲で書き、さらにわかったことが増えたら修正してゆこうと思う。 #include <Carbon/Carbon.h> int main(int argc, char* argv[]) 5. マニュアルはどこに プログラミングを続けてゆくと、知らない関数や構造体、メソッドやクラスが出てくる。そういう時、UNIXならばman ***としたりman -k ***とすればわかる。IRIXだとさらにBook Shelfというのがあって、そこに開発用のドキュメントが一式揃っている。しかしMac OS XのTerminalでmanとしても出てくるのはBSD UNIX関連のものだけだ。Carbon関連は出てこない。ではどうやって情報を入手するのか。 5.1 ADCで検索する ADCのサイトに入るとほとんどのページで上部に検索用の枠がある。ここに関数名を入力してエンターキーを押すと、関連するドキュメントが検索される。Googleを使って検索しているらしく、だいたい上位に良い解説文がヒットする。ただし全部英語である。それに、単にヘッダファイルをWebページにしただけのようなものもあり、それがけっこうな頻度でヒットする。これでは何に使うのかはわからない。それでもmanの代わりに使う頻度はこれがもっとも多い。なお、デベロッパーツールをインストールすると、その時点の最新の関連文書がHDにインストールされる(/Developer/Documentation)。たとえば、QuickDrawの事がしりたければ、/Developer/Documentation/Carbon/graphics/QuickDraw に関連文書がある。これにSharlockをかければ同じような環境になる。しかしネットワークの文書は更新されるので、ネットに接続した環境ならばADCで検索する方が良い。 5.2 Project Builderで検索する Project Builderには強力な検索機能がある。プログラミング中にちょっとわからなかったり、忘れたりした場合には、これを使う。検索窓に関数名などを入れて検索するとすごい速度で、今扱っているプロジェクト内をすみずみまで探してくれる。実は標準の検索だと、External Frameworkの中もガンガンに検索してくれる。このExternal Frameworkの中には、Mac OS Xで使えるライブラリのヘッダーファイルが網羅されている。なので、直接ライブラリヘッダーを検索できることになり、引数がわからなかったりした時にとても便利だ。何にしろすごく速いので多用する。ちなみにExternal Frameworkに関してはもっと詳しく後述する予定。 5.3 Googleで検索する 実は直接Google(www.google.com)で関数名を検索することも多い。そうするともちろんトップにはADCのページがヒットするが、下の方にAppleでないプログラマ達が公開しているソースコードなどがヒットすることが多い。解説がついていたりするので、大変役に立つ。 5.4 ADCのメニューを辿る それぞれのライブラリがどういうことを担当しているかがだいたい分かってきたら(そこまで達するのがけっこう大変)、ADCのメニューから解説文書を辿れば良い。簡単なプログラムを作るのであれば、あまり詳しくOSの構造を知る必要はないが、普通とは違う機能を加えたくなると、やはりある程度知らないとだめだ。その意味で「入門Carbon」の最初のあたりの章は重要だと思う。コンパクトに解説されていて見通しが良くなる。今は使わないライブラリでも、それがあることをしっているだけで、後で全然違う。 6. イベントハンドラを使う 上述のチュートリアルの温度変換ソフトや、「入門Carbon」の月旅行プランソフトなどの玩具ソフトを作った後で、まず最初に思ったのは、Interface Builderに用意されている他のインターフェース要素を使うにはどうすれば良いだろうか、というものである。 インターフェース要素のことをコントロール(Control)というのだが、その使い方は一応Developer/Examples/Carbon/AppearanceSample にある。ほぼすべてのコントロールの扱い方が網羅されている。しかしそのためにコードが大きく、複雑になっている。なぜ小さなばらばらのサンプルプログラムにしなかったのだろう。読み解くことも練習になる、という意味だろうか。それとも単なる手抜き?またCarbon Event Handlerスタイルではなくて、WaitNextEventスタイルの古い方法が取られている。Carbon Event Handlerスタイルだと、WaitNextEventをプログラマが直接呼ぶことはない。 しかし何はともあれCarbonでさまざまなコントロールを使いこなすには、このAppearanceSampleがわからなければ仕方がないので、解読しつつ、スライダーを使う簡単なプログラムを自作することを最初のステップとした。その前に、まず本章では、Carbon Event Handlerの説明と、もっともシンプルなイベントハンドラを使ったアプリケーションの作り方について解説する。 6.1 Carbon Event Handlerとは さてどのプラットフォームで開発をするにしろ、イベントハンドラというのは、避けて通れないものである。どれにでもある。開発者でイベントハンドラを知らない人はいないと思うが、おおざっぱな解説をしておく。 普通のアプリケーションというのは、人間が指令(コマンドやマウス処理)を与えて、仕事をしている以外の時間は何もしていない。そして、その何もしていない時間というのがとても多い。たとえば電卓プログラムでは、数字ボタンを押されたら瞬時に数字を表示する。しかし次の入力までは何もすることがない。また+ボタンなどが押されると計算結果を即座に表示する。そして訓練中の犬よろしく次の指令を待ち続ける。これを待っている間ループにしてプログラミングすると、他のことが何もできなくなる。他の事というのは電卓を使いながらワープロで文書を入力したり、Webページを閲覧したりする、ということだ。だから、電卓アプリは何か指示が来るまではループをしたりしてはいけないのだ。 そのために、OSは、何もやっていないアプリケーションが安心して休めるように指示を集中して受け付ける窓口をやっている。その窓口にやってくる指令がイベントである。 Carbon Event Handlerでは、上述のプログラムで、RunApplicationEventLoop();が呼ばれると、プログラムは窓口をOSに渡して、待ちの状態に入る。OSは待ちに入ったアプリケーションにはCPUの演算をさせない。完全に眠った状態だ。(細かくは眠った状態にも何種類かあるが)このあたりの解説は「入門Carbon」にあり、より詳しいし、正確なのでぜひ読まれることをおすすめする。 では眠ってしまったアプリはどうやって起きるのか、というとイベントハンドラというものを使うのである。イベントハンドラというのはモーニングコール依頼のようなものだ。「こうこう、こういうイベントがやってきたら起こして下さい」という風に記述してRunApplicationEventoLoop()を呼び出す前にOSに渡しておく。そうすると、そのイベントが発生すると、例えばアプリのボタンの所にマウスポインタがやってきて、クリックイベントが発生したりすると、OSは「さて、このイベントは誰に渡すんだっけ」ということで、依頼票を見渡して、眠っているアプリを起こすことになる。 この仕組みは最近の計算機ならばどれでも同じである。Carbon Event Handlerというのは、Carbon環境で導入された新しいイベントハンドラである。従来はWaitNextEventという関数をアプリが明示的に呼び出すことでイベントをもらっていたが、このCarbon Event Handlerでは、そういうのがない。RunApplicationEventLoop()を呼び出したら、もう何もしない。その分、OSが良きにはかってくれる。OS Xのマルチタスク処理性能は高いので、まかしておけば無駄なことにCPUを使わない、結果としてパソコンのユーザはスムーズにパソコンを使えることになる。何もやっていないのに、いつまでもCPUの処理を続けるアプリがあると、他の作業がどんどん重くなる。そのためにもなるべくCarbon Event Handlerを使った方が良いらしい。 6.2 イベントハンドラの使い方
#include <Carbon/Carbon.h> 基礎となるのはInstallEventHandlerという関数(windowが抜けている)である。イベントは、「何に対して」「どういう」イベントか、で区別される。その「何に対して」の部分はさまざまである。中でもアプリケーションではwindowに対して起こるイベントが最も頻度が多い。そこでウィンドウ用の関数(実は中でInstallEventHandlerを呼び出すマクロ)が定義されている。 第一引数のwindowは、どのウィンドウに対してか、という情報を表す。この場合はInterface Builderで作って、CreateWindowFromNibで呼び出したメインウィンドウwindowである。第二引数は、イベントハンドラへの参照子である。NewEventHandlerUPPという関数にハンドラ名を渡して作ってもらう。UPPというのはuniversal procedure pointerというやつで任意のハンドラ(プロシージャ)への参照子になる。次の"1"は受けつけるイベントの数で、この場合は一つだけ、上述のcommSpecである。その次に受けつけるイベント型変数へのアドレスを渡す。その次のwindowというのがuserDataである。今回windowを渡して、返事を書くテキストフィールドをそこから辿るために使う。最後はEventHandlerRefへのポインタを入れるらしいが、使っていないのでNULLとしておく。 以上。 --------------TO BE CONTINUED--------------- (c) few01@mac.com --[2002/1/27]-- |
|||