Ko-Window プログラミング予備知識編 ここでは具体的なプログラミングの説明には深入りしません。プログラミングの実 戦に入る前に、軽くでいいから Ko-Window の全体を見渡しておきたい、という方は 読んでおいて下さい。 ●ウィンドウ ウィンドウとは1つの独立した座標空間です。すべてのウィンドウは HOME 位置を 原点としたワールド座標を持っており、そのうちビューポートで指定される領域のみ が四角い範囲を通して見ることができます。 ●階層ウィンドウ 1つのウィンドウの中に小さなウィンドウをぽこぽこ開くことができます。中に開 いたものを親ウィンドウに対する子ウィンドウといい、このようにいくつでも階層構 造を持つことができます。子ウィンドウはあくまで親ウィンドウのビューポート空間 の中に存在しているので、決して親ウィンドウの外にはみでることはありません。 +------------------+ | 親ウィンドウ | | | | +------+ | | | 子 | | | +------+ | | | +------------------+ 1つの親に対して複数の子ウィンドウ(兄弟関係)を開くことができます。この兄弟 ウィンドウ同士は対等の立場ですが、それぞれみな重なりの順番を持っており、上に なっているものほど優先度が高くなります。 ●ルートウィンドウ 画面全体のことをルートウィンドウといいます。つまり DISPLAY画面は1つの大き なウィンドウであり、プログラムがその中に開くアプリケーションウィンドウは全部 ルートウィンドウの子に相当します。 多くのアプリケーションはさほどウィンドウに階層を持たずに、ルートの子供とし て1つだけウィンドウを開きそれで完結しています。これが最も単純なアプリケーショ ンの形です。 ●ウィンドウを開くには WindowOpen() 関数を呼び出します。ただし、これにはバリエーションがあり、以 下のように用途によって使い分けます。 WindowOpen() 何も飾りもつかず、純粋にウィンドウのみ開きま す。実用上は直接これを呼び出したり直接ルート の下に開くことは少ないでしょう。 WindowSimpleOpen() 浮き上がったようにウィンドウ枠がつきます。タ イトルバーのないウィンドウはほぼ間違いなくこ の関数で開かれています。 WindowTitleOpen() もっとも標準的なアプリケーションウィンドウで す。SimpleOpen() 同様の枠に加え、タイトルバー がつきます。 WindowScrollOpen() スクロールバーつきのウィンドウを開きます。ただ し枠もタイトルバーもありません。普通は WindowSimpleOpen() や WindowTitleOpen() の中 に子ウィンドウとして開き、任意の場所をスクロー ルさせるのに使います。 Command.win や view.win では WindowTitleOpen() の中に子ウィンドウとし てぴったり合うように開かれています。 Ko-Window では、ウィンドウを開くための関数はこの4つしかありません。これら 全部の関数に共通するパラメータは、親に対するドット座標、ドットサイズ、そして 親ウィンドウのID指定とイベント実行関数です。 ●イベントとは Ko-Window のプログラムはすべて受け身です。1つのウィンドウプログラムに対し て、ユーザーの操作が行われたと判断した時点ではじめて、サーバーがウィンドウの 指定ルーチンを呼び出します。例えば、マウスが押された、キーが押された、画面を 書き直さなければならなくなった、等。これらの、起点となるユーザー操作について の情報がウィンドウに送られてくることを総称してイベントと呼びます。 これは割り込みルーチンを予め用意しておいて、外部要因で割り込みが発生した時 に必要に応じてそれぞれのルーチンが実行される場合によく似ています。イベントと いう言葉を「割り込み」に置き換えて読み進むと(一部の方には)分かりやすいかもし れません。 ●イベントドリブンのイメージ ウィンドウはすべて、開く時にそのウィンドウの処理を行うイベント関数を登録し ます。例えば (A)ウィンドウの上でマウスの左ボタンが押されたら、サーバーは (A) ウィンドウに登録された「マウスの左ボタンが押された時のイベント処理ルーチン」 を実行します。 +-------------------------------+ | ルートウィンドウ | (A)ウィンドウのイベント処理ルーチン | | もしマウス左ボタンが押されたら | +------+ | ○○の処理をする | | (A) | | もしキーが押されたら | +------+ +------------+ | ○○の処理をする | | | | : | | (B) | | | | | | (B)ウィンドウのイベント処理ルーチン | +------------+ | もしウィンドウ位置を変更したら +-------------------------------+ ○○の処理をする ウィンドウは1つのオブジェクトであり、イベントはそれに対するメッセージであ るともいえるでしょう。 ●イベント関数で記述可能なもの 送られてくる可能性のあるイベントは以下の表にまとめた通りです。実際はこの中 から、アプリケーションが必要とする部分だけプログラムを書いて登録します。 例えばキー入力を使わないプログラムなら EventKey の処理ルーチンを書く必要は ありません。そのウィンドウが必要とするイベントと必要としないイベントを、 WindowSetEventAttr() 関数で設定することができます。いわゆるイベントマスクで す。この欲しいイベントを定義することを、そのウィンドウが○○のイベントを獲得 する、と表現することがあります。 ≪基本イベント≫ ウィンドウプログラムは、最低限以下の3つのイベントに対する処理ルーチンを持っ ています。(ものによっては無くても構いませんがここでは触れません) EventOpen ウィンドウを開く時一度だけ発生します。ここでウィンドウの初期 化を行っておくことができます。 EventClose EventOpen の逆で、ウィンドウを閉じる時に発生します。後始末は ここで行います。 EventRedraw 画面を書き直す時に発生します。このイベントでウィンドウ内のす べての表示が再描画可能でなければなりません。 ≪ユーザーオペレーションイベント≫ ユーザーの直接の操作に対するイベントです。プログラムがユーザーとの対話を行 うにはこれらのイベントのうち必要なものを獲得するよう処理ルーチンを書いておく 必要があるでしょう。 EventMouseSwitch マウスのボタンが押された(または離された)時に発生します。 EventMouseMove マウスカーソルの移動が行われた時に発生します。 EventMouseEnter マウスカーソルがウィンドウに入った時に発生します。ウィンドウ がフォーカスされたときのアクションを記述します。(Ko-Window で はさほど重要視されていない) EventMouseOut EventMouseEnter の反対にマウスカーソルがウィンドウから出た時 に発生します。 EventKey キー入力が行われた時に発生します。 ≪ウィンドウオペレーションイベント≫ これらは特に処理ルーチンを用意しなくても、デフォルトでそれなりの動作をして くれます。この操作が行われた時に特別な処理が必要だ、という場合に処理ルーチン を定義するために使います。(アセンブラのベクタテーブルを書き換える的な意味合 いでしょう) EventPop ウィンドウを1番上にする操作が行われた時に発生します。 EventPush ウィンドウを1番下にする操作が行われた時に発生します。 EventMove ウィンドウを移動する時に発生します。 EventResize ウィンドウの大きさを変更する時に発生します。 EventScroll ウィンドウ内部をスクロールする動作が行われた時に発生します。 ≪タイトルバースイッチイベント≫ これらはタイトルバーつきウィンドウで、それぞれのスイッチがクリックされた時 に発生します。イベントは発生しても、それがどういうアクションを起こすかはユー ザー任せです。オペレーションイベントとは異なり、処理ルーチンを定義しなければ 何もしません。 EventIconify アイコン化ボックスがクリックされた時に発生します。 EventZoom ズームボックスがクリックされた時に発生します。 ≪その他のイベント≫ EventInterval 他に何のイベントも発生していない時は、常にこのイベントが発生 します。ユーザー操作を起点としない唯一のイベントで、時計プロ グラムやリアルタイムに動いているように見えるプログラムは全部 このイベントによって駆動されています。 EventUser ユーザーがプログラム間で自由に動作を定義できるイベントです。 アプリケーションのウィンドウ操作に依存しない外部コントロール や、Clip Board 等のウィンドウ間通信はこれで実現されています。 (利用方法については user.doc や UserGraphic.doc 参照) EventGraphic 他のイベントと一線を画すもので、サーバーの状態変換を知らせる ために発生します。具体的にはグラフィックモードが変化した時に 起こり、グラフィック画面の色数に依存したプログラムが共存でき るよう協調をはかります。 ●プロセスとウィンドウの違い 今まで説明文中に「ウィンドウ」、「アプリケーション」等の言葉が混在していま したがここでその区別をある程度説明しておきます。 プロセス: Ko-Window 上で起動されるプログラムの単位です。1つのプロセス は必要に応じてウィンドウを何個でも開くことができます。しばし ばアプリケーションはこのプロセスと同じ1つのプログラム単位の 意味で使われます。 プロセスに対する外部からのリクエストを Signal といいます。ほ とんどの場合、SignalKill をプロセスに送ると、そのプロセスの開 いているすべてのウィンドウを閉じ、終了します。 プロセスがいくつ動いているかは Command.win の ps コマンドで確 認できます。現在の Ko-Window では最大プロセス数は 32 です。 (この限界値は単純にテーブルの個数なので、サーバーの再コンパ イルにて変更可能) ウィンドウ: 画面上に現れるオブジェクトの単位です。ウィンドウは必ず対とな るイベント処理関数を1つ持っています。ただし複数のウィンドウ が1つのイベント処理関数を共有している場合もあります。 ウィンドウに対する外部からのリクエストを Event といいます。 EventClose が即プロセスの終了にはつながりませんが、ウィンドウ を1つしか開かないアプリケーションではたいてい EventClose 時 にプロセス終了になるよう記述されています。(ConnectionClose()) プロセスとは違い階層構造をもち、ウィンドウの開ける数は、サー バーの割り当てるメモリの限界までです。プロセスのような固定値 の限界があるわけではありません。 注: ここでいうプロセスとは、Human68k でいうプロセスとは別ものです。Ko-Window 自体が Human68K のプロセスの1つとして動作します。その内部に Ko-Window 独 自のプロセス管理が存在します。また Ko-Window 上で BG 機能を使ったりすると また別のプロセス、という言葉が出てくる場合があります。 この辺の関係は、process.doc で説明します。 ●ウィンドウの座標系 ウィンドウは目に見えるものです。もちろん、敢えて見えないように設定する場合 もありますが、常に利用者に対する視覚的目的のために使われます。そのウィンドウ 内の表示は操作の指示としてドット位置による座標が用いられます。 これは HOME 位置を原点にし、左上をマイナス方向、右下をプラス方向で表し、そ れぞれのウィンドウが独自の座標系を持っています。これをウィンドウのローカル座 標と呼びます。 HOME 位置は WindowSetHome() 関数で変更可能なので、例えば HOME 位置を変更し てウィンドウの再描画を行えばウィンドウ内をスクロールさせることができます。 親ウィンドウからイベントが子ウィンドウに伝搬する場合、例えばマウスのクリッ ク位置等はそれぞれのウィンドウのローカル座標に変換されます。だからアプリケー ション側ではウィンドウが画面のどこにあるかに惑わされることなく、自分の世界だ けの処理に徹すれば良いことになります。 ●フォーカスウィンドウ フォーカスウィンドウというのは現在ユーザーが操作対象にして注目しているウィ ンドウのことです。例えばキーボードは1つしかありませんから、打ったキーがどの ウィンドウに送られればいいのかわかりません。 そこで現在注目しているウィンドウを1つに決め、キー操作はそこに送られるよう にします。Ko-Window ではこれはマウスカーソルが載っているウィンドウを意味しま す。よって、必ずしもフォーカスウィンドウが重なりの1番上になっているわけでも、 何か処理に特別扱いされているわけでもありません。 特に1つのウィンドウをフォーカスウィンドウとして認識させるには、関数 WindowSetFocus() を使います。この場合マウスカーソル位置と無関係に、キー入力 が常に指定したウィンドウに送られます。 ●ウィンドウ内描画コマンド サーバーによる描画は最小限のものに限られています。 DrawSetClear() ウィンドウ内を指定色で塗り潰します DrawSetSymbol() 文字列を指定位置に指定色の指定の大きさで描きます DrawSetLine() 線や函を描きます。塗り潰しや浮き沈みの指定ができます DrawSetPut() Sheet 型のグラフィックパターンを任意の位置に描きます DrawSetPattern() Sheet 型のパターンを繰り返して中を埋めます DrawSetCircle() 円を描きます (WSRV.X 2.24+10以降のみ) DrawSetDot() 点を打ちます (WSRV.X 2.24+10以降のみ) DrawSetGraphicClear() グラフィック画面を塗り潰します DrawSetGraphicLine() グラフィック画面に線やはこを描きます DrawSetGraphicPut() グラフィックパターンの転送をします DrawSetGraphicCircle() グラフィックに円を描きます (WSRV.X v2.24+10以降のみ) DrawSetGraphicDot() グラフィックに点を打ちます (WSRV.X v2.24+10以降のみ) ウィンドウ描画のメモリ上のイメージとして Sheet 型のバッファを持つことができ ます。この上では上記の同様の描画が Sheet 関数によってできます。(注:これはサー バーではなくライブラリが行います) ---- 1994 8/22 初期公開版 1994 12/19 若干の修正 1995 9/15 誤字および一部表現の修正 小笠原博之 oga@dgw.yz.yamagata-u.ac.jp DenDenNET: DEN0006 COR.