アプリケーションを組む方へ 補足説明 ------- イベントについて ●EventOpen  ウィンドウを開く時に1度だけ呼び出されます。 WindowTitleOpen( 0, 0, 100, 100, ..... , EventExec ); のように、ウィンドウを開く関数を実行すると、この関数の中で EventOpen が発生し ます。だから EventOpen から戻ってから、この関数も終了することになります。例え ば、 WindowID Wp; WindowMain() { int EventExec(); Wp= WindowSimpleOpen( 0, 0, 100, 100, NULL, EventExec ); } EventExec( wp, info ) WindowID wp; EventInfo *info; { switch( info->option ){ case EventOpen: WindowRedraw( wp ); return TRUE; case EventRedraw: : : } } のように用いようとしても、wp に WindowID が設定される前に EventOpen を実行し ようとするため、この場合は実行時にエラーになってしまいます(WindowID の実態は アドレスです)。ウィンドウを1つしか用いない場合はまず大丈夫でしょうが、複数 のウィンドウを扱う場合(特にクライアントデータの設定)には注意が必要です。 ●EventRedraw ウィンドウ上のすべての描画手続きは、このイベントで行なうのが原則です。初期 の頃の Ko-Window では、ウィンドウの移動等でも呼ばれていましたが、新しいもので はウィンドウの一部が隠れていたり、書き直しが必要な場合にのみイベントが発生し ます。 Ko-Window 上の表示はすべて DrawBuf に従って行なわれます。イベント発生の度に DrawSet 関数群で、DrawBuf にパラメーターを設定しても構わないのですが、アプリ ケーション使用中に決して変化することのないオブジェクトは、static に DrawBuf を確保しておくこともできます。例えば、EventOpen で static の DrawBuf に値を 全部設定しておいてから、EventRedraw では WindowDraw() だけ実行するということ が可能です。 例 #include #include WindowMain() { int EventExec(); WindowSimpleOpen( 0, 0, 100, 100, NULL, EventExec ); } EventExec( wp, info ) WindowID wp; EventInfo *info; { static DrawBuf dbuf[2]; switch( info->option ){ case EventOpen: DrawSetClear( dbuf, 1 ); DrawSetSymbol( dbuf+1, 10, 10, "Ko-Window", AttrDefault, 24 ); WindowRedraw( wp ); return TRUE; case EventRedraw: WindowDraw( wp, dbuf, 2 ); return TRUE; case EventClose: WindowClose( wp ); WindowConnectionClose(); return TRUE; } return FALSE; } 文字列を書き込む場合には、DrawSetSymbol() を使います。この時注意すべきことは、 DrawBuf を介して WindowDraw() に引き渡される場合に、文字列でなくて、アドレスが 渡されるということです。例えば、複数の文字列を一度に表示しようとして、 char strbuf[80]; DrawBuf dbuf[3]; DrawSetClear( dbuf, 1 ); sprintf( strbuf, "(%d,%d)", x, y ); DrawSetSymbol( dbuf+1, X1, Y1, strbuf, AttrDefault, 16 ); sprintf( strbuf, "(%d,%d)", h, v ); DrawSetSymbol( dbuf+2, X2, Y2, strbuf, AttrDefault, 16 ); WindowDraw( wp, dbuf, 3 ); のように書いても、思うように表示されません。DrawSetSymbol で行なっていること は、表示する文字列のアドレスを、DrawBuf に格納するということです。だから、上 記の例では dbuf[1] に書き込まれたアドレスも、dbuf[2] に書き込まれたアドレスも 同じ strbuf ですから、WindowDraw() で表示する時に単に同じ内容を2回表示するこ とになってしまいます。 char strbuf1[20], strbuf2[20]; DrawBuf dbuf[3]; DrawSetClear( dbuf, 1 ); sprintf( strbuf1, "(%d,%d)", x, y ); DrawSetSymbol( dbuf+1, X1, Y1, strbuf1, AttrDefault, 16 ); sprintf( strbuf2, "(%d,%d)", h, v ); DrawSetSymbol( dbuf+2, X2, Y2, strbuf2, AttrDefault, 16 ); WindowDraw( wp, dbuf, 3 ); このように書けば、問題なく表示できるでしょう。 Ko-Window 上では、常にグラフィック画面よりテキスト画面が手前にくるようにな っています。もしグラフィックに何か表示させたい場合は、テキスト画面に穴を明け てやる必要があります。Ko-Window のテキストには COLOR 2 に透明色が入ってます ので、COLOR 2 で描画した部分はグラフィック画面が見えることになります。もし、 ウィンドウいっぱいにグラフィックを表示したければ、 DrawSetClear( dbuf, 2 ); のように実行することになります。 グラフィック画面のパレットは、各ウィンドウ、各プロセスで食い違っていること があります。X のようにカラーマップを取り合うのではなく、純粋にカレントに来た ウィンドウのパレットに設定してかまいません。パレットを設定するタイミングは、 EventRedraw はもちろん、EventPop , EventMove でやるのが標準のようです。でも、 EventRedraw だけでもたいていの役割は果たします。 ●EventInterval 疑似マルチタスク処理を行なうためには、この EventInterval を使います。Ko の 場合、プロセスに EventInterval が渡される優先順位は臨機応変で、一番手前にある ウィンドウほど(一番使用者の目に付きやすいウィンドウほど)プライオリティが高 く設定されます。そのため、見掛け上の処理速度やレスポンスも非常に速く、プロセッ サの能力を効率よく引き出すことができます。  逆に、EventInterval といっても全てのウィンドウを必ず一周するとは限らないの で、処理の内容にかかわらずイベントが到達しにくいウィンドウが生じるのも事実で す。今のところこれを回避する手段はありませんが、個人で利用する範囲のウィンド ウを考えた場合、ほとんど問題にはなりません。(自分で時計を見て処理すれば大丈 夫です)  この EventInterval も、Ko のウィンドウにおいてはひとつのメッセージとして扱 われます。プログラム上では、イベントが来たらどんな処理をするというだけで、閉 ループにプログラムを組むことはできません。慣れないうちは、この辺の組み方で悩 むかもしれません。 ●EventUser ウィンドウ間通信の出入口です。EventUser を送る場合は、corlib の SendData を使用すると簡単です。Finder からのファイル名は、UserStrings で送られてきま す。Finder や Paste を使用してファイル名を受けたい場合は、次のようにすると いいでしょう。(得るファイル名は一度に1つに限る) case EventUser: switch( info->UserData ){ case UserStrings: (char*)info->ComBuffer=*(char**)info->ComBuffer; case UserPaste: case UserString: strcpy( file_name, (char*)info->ComBuffer ); : アクション部。たとえば、 fileread( wp, info, file_name ); WindowRedraw( wp ); : など (あくまで例です) } return TRUE; ●EventClose EventClose は、通常クローズボックスをクリックしたり、タイトルバーのポップア ップメニューで Close を選択した場合に発生します。自分で(プログラムで)クロー ズさせることも当然可能です。 WindowRedraw() という関数は、ただ EventRedraw を発生させているだけなので、 info->opeion= EventRedraw: WindowSendEvent( wp, info ); と等価でした。しかし、WindowClose() と info->opeion= EventClose; WindowSendEvent( wp, info ); はまったくの別ものになります。WindowClose() は純粋にそのウィンドウを閉じるだ けになります。つまり、WindowClose( wp ) を使用しただけでは、 EventClose は発 生しないことに注意して下さい。実際、EventClose のイベント処理部分で、 case EventClose: WindowClose( wp ); WindowConnectionClose(); return TRUE; のように WindowClose() 自身を呼び出していることが多くあります。 case EventClose: 後始末 WindowClose( wp ); WindowConnectionClose(); return TRUE; EventClose のイベント部分でプログラムの後始末をすることはよくありますので、プ ロセスの終了を含めてウィンドウを閉じる場合は EventClose を WindowSendEvent() しなければなりません。なお、signal を利用して、 WindowSendSignal( WindowProcessID, SignakKill, 0 ); と書いた場合は、そのプロセスに(この場合は WindowProcessID )に EventClose が 発生します。プログラムの終了にはこちらが便利でしょう。 ------- corlib.a 私の作成した独自のルーチンが入っています。呼び出し方法や詳しい使い方は、 corlib.h を参照して下さい。(使用例までのってます・・) ------- MiniTERM.a C言語で書かれたプログラムを、そのままウィンドウ上のアプリケーションにして しまおうという大胆なライブラリです。(ほとんど #define ですが)C言語の標準的 な入出力関数をサポートしていて、簡単なプログラムなら何も考えずにウィンドウ上 のアプリケーションになってしまいます。 スクリーンエディタの stevie.win (jstevie) や em.win (MicroEMACS)、rogue.win (jrogue) なども、このライブラリを駆使して作られています。 1991 7/6 小笠原博之