タイトル【小池邦人のプログラミング日記】2001/1/18<Carbon Event Managerを使う その4>カテゴリーCarbon/CF, 小池邦人のプログラミング日記
作成日2001/1/18 22:5:3作成者新居雅行
今回から、自作のCarbonアプリケーションにCarbon Eventを実装する作業にチャレンジしてみたいと思います。

さて、Macintoshの新機種も販売され、アップルサイトから無料アップデータもダウンロードできるようになったことから、一般ユーザにもMac OS 9.1が行き渡り始めました。ところが、この最新システムにインストールされているCarbonLibは、v1.1.1と言う中途半端なバージョンなのです。何故このようなバージョンが付属しているのかは謎ですが、多分CarbonLib 1.2の完成がMac OS 9.1 GM版に間に合わなかったのでしょう。さっそくネットのあちらこちらから、この新しいCarbonLibが原因であろうCarbonアプリケーションのトラブルが聞こえてきています。Appleサイトにアップされている英語版「CarbonLib 1.2」は、日本語システムにはインストールできないので、何らかトラブルに遭遇した人は、以下のサイトから「CarbonLib 1.2 SDK」を落とし、その中にあるCarbonLib 1.2に差し替えてみると良いかもしれません。

◇Developer - Development Kits
 http://developer.apple.com/sdk/

ただし、v1.2に差し替えたとしても問題が解決するとはかぎりません。これはしょうがないのです。なにせ、まだまだCarbonLibは作りかけですから(涙)。特に、日本語入力やプリントアウトに関しては曖昧な仕様と多くのバグが残っています。Appleには、早急にCarbonLib 1.3のSeedingを開始してもらいたいものです。

さて、Carbon Evantを実装する自作アプリケーションには「ViewJPEG」を選びました。これは、私のサイトでの連載「新ToolBox 100の定石」においてサンプルとして利用しているアプリケーションです。以前に、ProjectBuilderを使い、Mach-OベースのCarbonアプリケーションへと変身させたのもこれです。

◇新ToolBox 100の定石
 http://www.ottimo.co.jp/koike/ToolBox/

Carbon Eventに対応していないソースコードは、同サイトのライブラリにアップロードされていますので、そちらを比較対照に使ってください。まずはmain()ルーチンから見てみます。

 

最初にGestalt()ルーチンにgestaltCarbonVersionパラメータを渡し、システムにインストールされているCarbonLibのバージョンをチェックしています。Carbon Event Managerは、CarbonLib 1.1から利用できるので、返された値(ver)がv1.1(0x110)以下だった場合には作業を中止します。比較する値をv1.2(0x120)にしてしまうと、Mac OS 9や現状のMac OS Xパブリックβでは起動できなくなりますので注意してください。引き続きGestalt()でチェックしているのは、QuickTimeのバージョンです。

通常では、main()ルーチンの最後でメインイベントループへ突入するのですが、Carbon Event ModelではEvent授受の機能を開始するためにRunApplicationEventLoop()を呼びます。ついでに、このアプリケーションの終了時に呼ぶdoQuit()ルーチンも見てみます。ExitToShell()で作業を終了する直前に、QuitApplicationEventLoop()を呼び、Carbon Eventの機能を停止していることが分かります。

実際にCarbon Event Handlerを実装する前に、Carbon Event Managerが提供している便利なAPIを紹介しておきます。そのひとつが、TrackMouseLocation()です。これは、旧Event ManagerのGetMouse()とButton()を合わせたような便利なAPIです。引数にグラフポート(GrafPtr)を渡すと、そのポートでのマウスカーソルのローカル座標と、マウスボタンが離されているかどうかの情報を返してくれます。このAPIは、GetMouse()やButton()のようにCPUプロセスをロックしてしまうことはありません。よってAppleは、CPU時間を他のプロセスに回すためには、GetMouse()やButton()の代わりにTrackMouseLocation()を使うよう推奨しています。また、このAPIを使う限り、処理中にウィンドウへの描画が画面(モニタ)へ反映されないといったMac OS X特有の問題を回避することができます。

TrackMouseLocation()のサンプルとして、ViewJPEGのdragScrollImageWindow()ルーチンを紹介しておきます。

 

このルーチンは、マウスドラッグにる画像のフリースクロールを提供しています。ここで使われているTrackMouseLocation()は、マウスボタンが押されている間はマウスカーソルのローカル座標を返し、マウスボタンが離された時点(retにkMouseTrackingMouseReleasedが返された時点)で処理から抜け出します。TrackMouseLocation()は、マウスがクリックされており、加えてマウスカーソルが前の場所から移動した時だけ座標値を返します。ですから、EqualPt()などで前の座標と今回の座標を比較し、それらが異なった場合にだけ処理を行うといった手間を省くことができます。GetMouse()でマウスカーソルの座標を得ていた時には、必ずそうした判断が必要だったのです。

次は、InstallEventLoopTimer()です。このAPIを使えば、一定の間隔で実行したい処理ルーチン(EventLoopTimerUPP)をシステムに登録することができます。昔のメインイベントループでは、こうした処理を、イベントが起こっていない時やNull Eventの発生時に実行していました。Carbon Event Manaerではメインイベントループがありませんので、それの代役となる仕組みが必要になったわけです。例えば、一定間隔で呼ぶ必要があるシステム関連のルーチンとしては、IdleTextEdit()やIdleControls()などがあります。またアプリケーション側としては、マウスカーソルの座標を逐次ウィンドウ上に表示するとか、何かのオブジェクト(アイコンなど)を一定間隔で点滅させるとか、バックグラウンドでファイルへのアクセスをするとか、通常処理と平行して別処理を実行したいときに役立ちます。

ViewJPEGがインストールしているEventLoopTimerルーチンは、myTimerEvent()です。

 

このアプリケーションは一定間隔で呼び出さなくてはならない処理が無いので、実装したコントロールのためにIdleControls()だけを実行しています。例えば、myTimerEvent()の中でSysBeep()を呼び、指定した通りの一定間隔でビープが鳴れば、EventLoopが正常に機能していることになります。InstallEventLoopTimer()の引数には、処理の開始時間と間隔時間を渡します。どちらも、今まで利用してきたTick値(1/60秒)ではなく、EventTimeと呼ばれる浮動小数点値(double)です。よって、Tick値で指定したい場合には、TicksToEventTime()によりEventTimeに変換しておく必要があります。また、このようなEventLoopTimerルーチンは複数登録できますので、この仕組みを上手く活用すれば「Thread Manager」などを使わなくても、アプリケーションで簡単なThread処理を実現することが可能かもしれません。

TrackMouseLocation()やInstallEventLoopTimer()の利用方法や詳しい引数の内容は、Universal Interfacesの「CarbonEvents.h」にコメント文として記載されていますので参照してみてください。

 

次回は、ViewJPEGに「Carbon Event Handler」を実装してみます。いったいどのくらいのHandlerを用意すれば、一般的なアプリケーションが成り立つのかを調査してみたいと思います。
[小池邦人/オッティモ]
関連リンクオッティモ