タイトル【小池邦人のプログラミング日記】2001/1/23<Carbon Event Managerを使う その5>カテゴリーCarbon/CF, 小池邦人のプログラミング日記
作成日2001/1/25 14:23:11作成者新居雅行
今回は、ViewJPEGに「Carbon Event Handler」を実装してみます。まずはアプリケーション自身を対象とするEvent Handlerのインストールからです。その中心は、メニュー選択を処理するルーチンとなります。

2001年1月23日現在、Apple ADCメンバーサイトに「CarbonLib 1.2.5a3 SDK」と「Universal Interfaces 3.4b4」がアップロードされています。CarbonLib 1.2.5a3の方は、リリース内容が記載されているドキュメントを読んでみると、幾つかのバグが取れていることが分かります。ただし、実際に自作アプリケーションにリンクして調べてみたところ、CarbonLib 1.2で未実装だったCarbon Event Managerに関する機能は、未だそのままのようです。あちらこちらから不満が噴出している(特に日本では)CarbonLibですので、Appleには早急なバージョンアップと、次なるGM版の発表を望みたいと思います。

ところで、前回インストールしたタイマールーチンで、どのような状況ならばタイマーによる割り込みが継続されるのかを調べてみました。すると、その状況はMac OS 9とMac OS Xでは異なることが判明しました。Mac OS 9では、メニューを選択している最中(メニューアイテム表示中)はタイマーの割り込みが継続され、タイマールーチが呼ばれます。ところが、マウスドラッグによるウィンドウの移動やリサイズの最中には割り込みは発生せず、タイマールーチの実行もストップしてしまいます。それと比較してMac OS Xでは、メニュー選択に加えてウィンドウの移動やリサイズにおいても割り込みは発生し続け、タイマールーチの実行がストップすることはありません。何故に、Mac OS 9ではダメなのに、Mac OS XではOKなのでしょうか?

例えば、タイマールーチンでウィンドウ上にマウスカーソル座標を逐次描画しているとします。この時、QuickDraw描画ルーチンに必要な情報は、ウィンドウのグラフポート(CGrafPtr)です。Mac OS 9でウィンドウを移動すると、このグラフポートに保存されている情報(PixMapのメモリードレスなど)が変化してしまいます。加えて、移動やズームではウィンドウ枠しか表示されず、そうした最中のQuickDrawによる描画は不可能となります。ところが、Mac OS Xではウィンドウサーバが働いているため、ウィンドウへの描画とモニター(画面)への描画は同等ではありません。QuickDrawによる描画は、まずはウィンドウ領域が保存されているオフスクリーンへと行われ、その後にモニターのフレームバッファへと画像転送が行われるわけです。そのため、Mac OS Xでは、ウィンドウがモニター内を移動している最中でも、QuickDrawの描画対象(CGrafPtr)には変化が無く、それによる弊害も生じないわけです。

さて、話しをViewJPEGへのCarbon Event Handlerの実装に戻します。メニュー選択でCarbon Eventを発生させるのには、各メニューアイテムにコマンド(OSType)を割り振る必要があります。コマンドは、SetMenuItemCommandID()により、ソースコード内で追加しても構わないのですが、通常は‘xmnu’リソースとして準備しておきます。ViewJPEGでは、Appleメニュー(ID=128)とFileメニュー(ID=129)の‘xmnu’リソースを準備しています。加えてID=130というリソースも用意されていますが、これはアプリケーションをMac OS Xで起動した時に使う「Quitを外したFileメニュー」に対応させるためです。

 

私は最初、このID番号のリソースを定義するのを忘れていたため、Mac OS Xでのメニュー選択でCarbon Eventが発生せず、しばらくの間「Mac OS X側のバグなのか?」と悩んでしまいました。みなさんも注意してください。

‘xmnu’リソースで割り振られているコマンドを、Carbon Event Manaerでは「HI Command」と呼びます。こうしたコマンドはメニューアイテムだけではなく、ウィンドウ上のコントロール(ボタンなど)にも割り振ることができます。HI Commandには、作業終了は‘quit’、カットは‘cut ’、OKボタンは‘ok ’といった具合に、システム側でタイプが決められているものもあります。使いたい用途のHI Commandが定義済みかどうかは、Universal Interfacesの「CarbonEvents.h」をチェックしてください。

 

以前にお話した「BasicCarbEvents」サンプルの‘quit’コマンドには、「Standard Handler」(ディフォルト処理)として、Quit用のApple Event Handlerを呼び出す処理が用意されていました。将来的には、定義済みのHI CommandにはStandard Handlerが用意される(もう用意されている?)ことが予想されます。よって、アプリケーションで用意したメニューアイテムと同等のHI Commandが既に定義されていれば、それをそのまま利用するのが安全だと思います。

まず最初の仕事は、Carbon Event Handlerのインストールルーチンを記述することです。ViewJPEGでその仕事を行っているのが、setuUpApplicationEvent()ルーチンです。

 

選択されたメニューアイテムのHI Commandを受け取るためには、EventTypeSpecのeventClassに「kEventClassCommand」を、eventKindに「kEventCommandProcess」を代入し、InstallApplicationEventHandler()でHandler名と伴にインストールします。今回は「おまけ」として、EventTypeSpecに「kEventClassMouse」と「kEventMouseMoved」のペアーも代入し、マウスカーソルが移動した時のCarbon Eventも受け取れるようにしてみました。こうしてインストールした2種類のCarbon Eventを処理するためのEvent Handlerルーチンが、myApplicationEventHandler()となります。

 

ルーチンの先頭では、GetEventClass()とGetEventKind()により、処理分岐に使うためのeventClassとeventKindをEvent情報(EventRef)から得ておきます。マウスカーソルが前の位置から移動したことは、この2つのパラメータに、kEventClassMouseとkEventMouseMovedが返ることで判断できます。そこで、GetEventParameter()でEvent情報からマウスカーソル座標(Point)を抽出し、menteCursor()へと処理を渡します。

 

menteCursor()では、マウスカーソルの形状変化を管理しているのですが、マウス位置が変わった時にしかこの処理は呼ばれませんので、CPUパワーの無駄づかいを防ぐことができます。

同じくメニューが選択されたことは、2つのパラメータにkEventClassCommandとkEventCommandProcessが返る事で判断できます。やはり、GetEventParameter()でEvent情報からHI Commandを得て、それをdoMenu()に渡して処理させます。doMenu()では、この値を使い、Case文で適切な処理へと分岐させます。

 

ここまで来れば、今までのメニュー分岐処理と大差ありません。GetEventParameter()により、どんなeventKindでどのような情報を抽出できるのかは、CarbonEvent.hのコメント文に記載されていますので参照してください。

 

本当ならば、この仕様に関しても詳しいドキュメントが欲しいところですが、Carbon Eventの仕様の不確定さが、正式なドキュメントの発表を阻害しているような気がします(涙)。

次回は、画像ウィンドウに対応したCarbon Event Handlerを実装してみます。Carbon Eventの発生を引き金に実行される、ウィンドウのクローズ、ムーブ、リサイズ、ズームといった処理を調べてみます。
[小池邦人/オッティモ]
関連リンクオッティモ