タイトル【小池邦人のプログラミング日記】2000/8/27<Mac OS Xへの道 Carbon対応の実際(6)>カテゴリーCarbon/CF, 小池邦人のプログラミング日記
作成日2000/8/31 10:28:5作成者小池邦人
既存のソースコードをCarbon APIに対応させ、Mac OS X環境でも起動できるアプリを作るための工程のうち、今回は(8)新しいEventモデルへの変更について解説します。

(8)新しいEventモデルへの変更

CarbonLib v1.04を用い、今まで説明してきた工程に従えば、Mac OS Xでちゃんと動くアプリケーションが開発できたはずです。これがMac OS Xでちゃんと動かないとなると、Mac OS XへのCarbon APIの実装にバグがあることになります。しかし、現状のMac OS XがまだDP4(デベロッパ・プレビュー版)であることを考慮すれば、厳密なチェックは少々可哀想です。Appleの言葉を信じれば(笑)9月中にはMac OS Xのパブリックβ版が発表されるはずですので、とりあえずそれを待ち、CarbonLib APIの実装状態を厳しくチェックしてみたいと思います。

さて、CarbonLib v1.1(現状はαバージョン)から新規に「Carbon Event Manager」がサポートされました。この新しいEventモデルは、今までのようなイベントループによる分岐を使わず、Apple Eventで用いた手法を拡張し、発生したEventを各オブジェクトに対応させたEvent Handlerで処理する設計になっています。例えば、ユーザがウィンドウ(オブジェクト)上の、Close Box、Zoom Box、Grow Boxなどをマウスクリックした時でも、Event Handlerとして登録されているルーチンが処理することになります。あらゆるオブジェクト(ウィンドウ、メニュー、コントローラ、ダイアログ)に対するEvent処理を、すべてこの仕組みで統一しようというのが新モデルの目標です。

当然ですが、今まで利用してきたイベントループとWaitNextEvent()を使った旧Eventモデルでも、ちゃんとMac OS X用のアプリケーションは開発できます。以前にお話した「Carbon Print Manager」や「Carbon Scrap Manager」のような強制書き換えは必要ありません。ただし、Mac OS XではCarbon Event Managerを利用した方がアプリケーションのパフォーマンスが向上するようです。つまり(8)の「新しいEventモデルへの変更」の工程は(9)の「Mac OS Xに対応する最適化」に含もまれるわけです。しかし、作業量が非常に大きくなるので、わざわざ別工程として抜き出してみました。

現在のCarbonLib v1.1a4 SDKには、Carbon Event Managerに関する詳しいドキュメントは含まれていません(涙)そこで、AppleのCarbon Documentのサイトを見てみると、以下のアドレスにCarbon Event Managerに関するドキュメントが登録されていることがわかります。

◇Carbon Event Manager
 http://developer.apple.com/techpubs/carbon/oss/CarbonEventManager/carboneventmanager.html

このうち「Carbon Event Manager Preliminary API Reference」は、APIや定数に関するリファレンス的な説明がHTMLにより記載されています。このドキュメントと、ユニバーサルヘッダーファイルの「CarbonEvents.h」を参考にすれば、Carbon Event ManagerにどのようなAPIが存在するのかは、だいたい把握することができます。もうひとつの「Introduction to the Carbon Event Manager [PDF]」の方で、こうしたAPIの使い方を詳しく解説しているだろうと見てみると、見事に期待を裏切られます。何とこのPDFファイルは、たった5ページの内容しかないのです。恐ろしく貧弱な内容なのですが、このドキュメントが言っている事を簡単にまとめると以下のようになります。

(1)Mac OS Xでのパフォーマンスを上げるならCarbon Event Managerを使え。
(2)マウス座標の入手はGetMouse()の代わりにTrackMouseLocation()を使え。
(3)押されたキーの内容をチェックするためだけに待ちループを作るな。
(4)定期的に割り込む必要がある処理はInstallEventLoopTimer()で登録しろ。

(1)に対応するための最初の手順はRunApplicationEventLoop()を呼ぶことです。するとアプリケーションのEvent管理は、QuitApplicationEventLoop()を呼ぶまでOS側に移管されます。つまり、アプリ側でイベントループを用意して処理分岐をさせる必要はないのです。この新しいEventモデルへの移行には、あらゆるイベントに対するEvent Handlerが必要です。こうしたHandlerの大部分は、今までのEvent処理ルーチンの書き直しで済むとは思いますが、それにしても大きな変更となります。Carbon Eventモデルの雰囲気を知るのには、SDKのSample Codeフォルダにある「BasicCarbEvents」や「SimplerText」といったサンプルプロジェクトを参考にしてみてください。

(2)は、メインイベントループから外れた所でマウス座標を得る手段を、GetMouse()からTrackMouseLocation()へ切り替えろということです。今までの...

 while( StillDown() )
 {
    GetMouse( &loc );
 }

等を、

 TrackMouseLocation(curPort,&loc,&result );
 while (result !=kMouseTrackingMouseReleased )
 {
    TrackMouseLocation(curPort,&loc,&result );
 }

へと書き直します。StillDown()やGetMouse()はプロセスに対するオーバーヘッドが大きいので、Mac OS Xでは推奨されないと言うことでしょう。

(3)は、特定のキーや特殊キー(オプションやコントロールなど)が押されれているかどうかの判断を、あちこちで行うことは止め、ちゃんとEvent Handlerとして登録しろという事です。ドキュメントには以下のようなEvent Handlerを登録するサンプルが記載されています。このようなキー入力の待ち処理もオーバーヘッドが大きいわけですね。

const EventTypeSpec kMyKeyModsChanged={kEventClassKeyboard,kEventKeyModifiersChanged };

InstallEventHandler( GetApplicationEventTarget(),NewEventHandlerUPP( myKeyModsChanged ),1,kMyKeyModsChanged,NULL,NULL );

(4)はイベントループで定期的に処理していたルーチン(カーソルの切り替えやアニメーション、テキスト入力時のインサーションポインターの点滅、プログレスバーのアニメーションなど)はInstallEventLoopTimer()で登録して処理しろという事です。

if( ! WaitNextEvent( everyEvent,theEvent,60,NULL ) )
 myDoIdle();

などと記載していた箇所は...

InstallEventLoopTimer( GetCurrentEventLoop(),0,60,NewEventLoopTimerUPP( myDoIdle ),0,timerRef );

と、InstallEventLoopTimer()で処理ルーチンを登録しておけば、それをいちいち呼び出さなくても、指定した時間間隔で定期的に実行されるわけです。

実際に対応しなければいけない変更点は、まだまだ沢山あるような気もしますが、とりあえず上記箇所の優先順位が高いようです。CarbonLib v1.1 SDKのサンプルプロジェクトでは、Carbon Eventモデルの「雰囲気」は味わうことはできますが、詳しい解説書なしでのアプリケーションへの大規模な導入は無理だと思います。Appleには、Carbon Event Managerに関する詳しいドキュメントの早急な配布を強く要望したいと思います。

次回は(9)の工程についてお話しする予定です。「新Eventモデルへの変更」以外の「Mac OS Xに対応する最適化」と最新のCarbon SDKについての解説です。
関連リンクオッティモ