● 小池邦人のMac OS Xへの道 2000/07/26

〜 Carbon対応の実際 その2 〜

既存のソースコードをCarbon APIに対応させ、Mac OS X環境でも起動できるアプリを作るための工程のうち、今回は(3)と(4)の工程について解説します。

(3)WinodwPtrとGrafPtrを明確に区別

まずは、古いソースコードのどこかに、まだ「GrafPtr」の定義が残っているなら、Carbon環境に移す時にすべてを「CGrafPtr」に変更しておくと良いでしょう。ToolBoxの新しいAPIには、引数にCGrafPortしか受け付けない(キャストすれば大丈夫なのですが)強情なやつもいますので、Carbon化のタイミングでGrafPtrを絶滅させておくのが得策です。

さて、今までの環境では、SetPort( window )といった具合に、SetPortに直接WindowPtrを渡してもエラーにはなりませんでした。ところがCarbon環境では、こうした処理は許されていません。それを補うために、以下のようなAPIが用意されています。

void SetPortWindowPort(WindowPtr window);
WindowPtr GetWindowFromPort(CGrafPtr port);

同様に、DialogPtrもWindowPtrとほとんど区別無しで扱われてきましたが、Carbon環境ではきっちり区別します。という事は、当然CGrafPtrとも区別する必要がありますので、以下のようなAPIが用意されています。

void SetPortDialogPort(DialogPtr dialog);
DialogPtr GetDialogFromWindow(WindowPtr window);

あまり実用的な例ではないのですが、CGrafPtrからDialogPtrを得るには以下のように記述します。残念ながらGetDialogFromPort()というAPIはありません。

dptr=GetDialogFromWindow( GetDialogFromWindow( port ) );

またCarbon環境にかぎった話しではないのですが、異なる色数(デプス)のCGrafPort間で画像を転送したり、PixMap画像をオリジナルとは異なる色数のウィンドウへ転送する場合、もしくはモニターの色数と異なる色数のCGrafPort(モニターが1600万色でCGrafPortが256色など)にQuickDrawを利用して描画するような場合には、GetPort()とSetPort()を使わずに、GetGWorld()とGetGWorld()を使います。こうしないと、ユーザがモニターの色数を切り替えた時、起動中のアプリで描画の不都合が起こることがあります。ただし描画処理がからんでいない場合には、引き続きGetPort()やSetPort()を使っても特に問題はありません。

(4)アクセッサーファンクションの利用

Carbon環境では、ToolBoxなどで定義されている構造体のメンバーには直接アクセスできなくなりました。ユーザが構造体のメンバーの入出力を行には、代わりに各構造体メンバー用として定義されたアクセッサー(accesspr function)を使います。例えば、WindowRecordの先頭のGrafPortを得るには以下のアクセッサーを利用します。

CGrafPtr GetWindowPort(WindowPtr window);

同様に、DialogRecordの先頭のWindowRecordを得るのには、以下のアクセッサーを利用します。

WindowPtr GetDialogWindow(DialogPtr dialog);

構造体メンバーに対して、どのようなアクセッサーが定義されているかは、CarbonPortingGuideにまとめられています。しかしそれを参照するよりは、その構造体が定義されているManagerのUnversal Headerファイルを検索し、構造体メンバーの横にコメント文で記述されているアクッセッサー名を見るのが近道で確実でしょう。例えば、Dialogs.hに定義されているDialogRecord構造体を見ると、そのメンバーの横に対応しているアクセッサーが記述されています。

struct DialogRecord {

  WindowRecord window;   /* in Carbon use GetDialogWindow or GetDialogPort*/
  Handle     items;    /* in Carbon use Get/SetDialogItem*/
  TEHandle    textH;    /* in Carbon use GetDialogTextEditHandle*/
  SInt16      editField;  /* in Carbon use SelectDialogItemText*/
  SInt16     editOpen;   /* not available in Carbon */
  SInt16     aDefItem;   /* in Carbon use Get/SetDialogDefaultItem*/
};
typedef struct DialogRecord DialogRecord;

最後にアクセッサーを利用したサンプルを示しておきます。どちらもCopyBits()を利用して、オフスクリーンのCGrafPortからウィンドウへ画像を転送する簡単なルーチンです。oldCopyTest() ルーチンが今までのMac OSでのやり方であり(かなり古典的です)、newCopyTest()がCarbonLib用に変更を加えた物です。

void oldCopyTest(WindowPtr window,CGrafPtr off,Rect *srt,Rect *drt )
{
  CGrafPtr cptr;

  GetPort( &cptr );
  SetPort( window );
  CopyBits( &(off->portBits),&(window->portBits),srt,drt,srcCopy,NULL );
  SetPort( cptr );
}

void newCopyTest(WindowPtr window,CGrafPtr off,Rect *srt,Rect *drt )
{
  PixMapHandle spix,dpix;
  CGrafPtr port;
  GWorldPtr gptr;
  GDHandle ghd;

  GetGWorld( &gptr,&ghd );
  port=GetWindowPort( window );
  SetGWorld( port,NULL );
  spix=GetPortPixMap( off );
  dpix=GetPortPixMap( port );
  CopyBits( (BitMap *)*spix,(BitMap *)*dpix,srt,drt,srcCopy,NULL );
  SetGWorld( gptr,ghd );
}

本当ならCopyBits()内の(BitMap *)というキャストも外せると美しいのですが...。CarbonPortingGuideを読んでみると、CopyBits()の引数に関してはApple側にも色々と苦悩があるようです(笑)ソースだけを見ていると、ルールが厳しくなり融通が利かなくなった分だけ記述量が増え、はっきり言って良くなったのか悪くなったのか判断に悩むところですね。

次回は(5)以降の工程について解説する予定です。

copyright 2000 Ottimo, Inc. All rights reserved
無断転載・引用禁止
Contact Us: koike@ottimo.co.jp