はじめに
今回はGUIXの内部動作について書いていこうと思います。
GUIXとは、Express Logic社が開発した組込み向けのGUIツールで、比較的、性能の低い環境でも動作するように設計されています。
なお、Express Logic社はMicrosoft社に買収され、またMicrosoft社は、Azure RTOS テクノロジを Eclipse Foundation に提供しましたので、現在は「Eclipse ThreadX GUIX」となっています。(名称が長いので、本コラムでは「GUIX」と呼びます。)
以下に用語の説明を書いておきます。
# | 用語 | 意味 |
1 | ThreadX | 組込み向けのリアルタイムOS。 |
2 | Widget | GUIXのGUI部品を指す。Widgetを配置したり組み合わせたりすることでGUIシステムを作る。 |
3 | イベントハンドラ | GUIXの動作時に何らかのイベントが発生した場合に、GUIXシステムスレッドから呼ばれる関数。 デフォルトの動作は定義されているが、オーバーライドすることで独自の処理を記述できる。 |
4 | スレッド | ITRONで言うところのタスクの事。 |
5 | チック | ThreadXが管理するシステムタイマの最小単位。10ms、1msなどの設定が多い。 |
6 | トグルファンクション | GUIXが描画を終えたタイミングで呼ばれる関数。LCDドライバとのI/Fをポーティングする関数でもある。 |
7 | 描画ハンドラ | GUIXの動作時に描画が必要になった場合に、GUIXシステムスレッドから呼ばれる関数。 デフォルトの描画処理は定義されているが、オーバーライドすることで独自の描画処理を記述できる。 |
GUIXの内部動作
GUIXは内部で1つ、または、2つのスレッドが動作しています。
1つはGUIXの動作そのものを行うGUIXシステムスレッド。
もう1つはポーティング方法にも依存しますが、タイマスレッドです。
タイマスレッドはThreadXを使用する場合はThreadXのタイマ機能を使用するので、スレッドとしては作成されませんが、ThreadX以外のOSの場合はタイマスレッドを作成する場合もあります。

GUIXシステムスレッドの役割
GUIXシステムスレッドは、GUIXの動作そのものを行います。入力ドライバから送られてくるイベントの処理、Widgetの描画、ユーザーのイベントハンドラ、描画ハンドラの呼び出し、画面更新のタイミングでのトグルファンクションの呼び出しなどを行います。そのためGUIXシステムスレッドが動作できないと画面更新やタッチパネルなどのレスポンスが悪くなる要因になります。

GUIXシステムスレッドのイベント処理
GUIXのシステムでは、GUIXに対する入力(タッチパネルなどの入力機器や、タイマなど)は全てイベントという扱いになります。GUIXにイベントを送信するAPIが用意されていますので、これを利用します。
受信したイベントは、その種別によりGUIX内部でGUIXシステムスレッドが処理を行います。多くの場合はイベントハンドラを呼び出して処理されます。

GUIXシステムスレッドのイベントハンドラ
GUIXには多くのWidgetが用意されており、そのほとんどにイベントハンドラが用意されています。イベントハンドラは、GUIXが受信したイベントの内容に従い、適切なWidgetのイベントハンドラが呼び出されます。
例えば、画面上にボタンWidgetがあり、ユーザーがボタンをタッチしたとします。タッチされた情報はタッチパネルにより検出され、タッチパネルドライバにより座標が決定され、GUIXシステムスレッドにイベントとして送信されます。GUIXシステムスレッドは受信したイベントから座標情報を取得し、座標にあるWidgetのイベントハンドラを呼び出します。

GUIXシステムスレッドの描画
GUIXシステムスレッドは全てのイベント処理を終えると、描画処理を行います。イベント処理の中で画面の更新が必要と判断されると、再描画が必要なWidgetのリスト(後述のdirtyリスト)に追加されます。GUIXシステムスレッドはこのリストを参照しながら、各Widgetの描画ハンドラを呼び出します。GUIXの描画はWidget単位で行われますので、例えばWidgetが重なるような画面構成であっても、描画が必要とされた場合はWidget全体が描画されます。また、Widgetに親子関係がある場合は、親から子の順に描画されます。すべての描画を終えるとGUIXシステムスレッドはトグルファンクションを呼び出します。(この辺りは過去の記事に記載していますので参照ください。)


GUIXシステムスレッドの動作のまとめ
まとめると、GUIXシステムスレッドは受信したイベントを処理し、メモリへ画面描画を行うシステムと言う事になります。
GUIXイベントの内部動作と注意点
GUIXには様々なイベントが定義されています。Widgetの表示を指示したり、隠したり、スクロールを支持するものなどがあります。その中には受信したイベントの処理の結果、別のイベントを生成するものもあります。
例えば、ボタンWidgetをタッチ、離す動作をした場合、タッチパネルドライバからは、GX_EVENT_PEN_DOWN、GX_EVENT_PEN_UPという2つのイベントが送られてきます。ボタンWidgetのイベントハンドラはこの2つのイベントを受けて、新たにGX_EVENT_CLICKEDイベントを生成する、といったようになります。これによりユーザーのイベントハンドラでは、タッチ関連のイベントを処理するのではなくGX_EVENT_CLICKEDを処理すれば良いようになります。
イベントはイベントハンドラで処理されますが、処理しなかった場合は親Widgetのイベントハンドラに渡されます。親Widgetのイベントハンドラでも処理されなかった場合はさらに親Widgetのイベントハンドラに渡されていき、最終的に親がいなくなった時点で消滅します。この呼び出しはC言語的に行われますので、親子関係が深い構成の場合はGUIXシステムスレッドのスタック量も検討する必要があります。
また、イベントはOS機能のデータキューとして送受信されます。そのため貯められるイベント数は有限になりますので、GUIXシステムスレッドが長時間動作できないとデータキューが満杯になり、イベントが送信できない現象が起きます。ですので、システム全体としてGUIXシステムスレッドが動作できるような設計を行うことが必要になります。
GUIX描画の内部動作と注意点
GUIXではイベント処理と描画処理は分けられています。すべてのイベント処理が終わって(イベントのデータキューが空になって)から描画処理が行われます。なのでイベント処理時にはキャンバスメモリの更新はされません。イベント処理の中では描画が必要なWidgetをリストに登録するのみです。
GUIXの描画ではdirtyリストと呼ばれる、再描画が必要なWidgetポインタを登録しておくリストがあり、このリストに従い再描画が行われます。dirtyリストには再描画が必要なWidgetが登録されますが、親子関係の中で再描画が必要な親のみが登録されます。例えば、WindowWidgetの中にボタンWidgetがある場合、Windowとボタンは親子関係ですが、ボタンのみ再描画が必要な場合は、dirtyリストにはボタンWidgetが登録され、再描画自体もボタンWidgetのみ行われます。ですが、WindowWigetの再描画が必要な場合はdirtyリストにはWindowWidgetが登録され、再描画はWindowWidgetとボタンWidgetが行われます。ですので、画面全体を覆うようなWindowWidgetの背景画像を設定している場合などは、毎回全画面更新が発生する可能性がありますので注意が必要です。
また、画像に関して、GUIXにはJPEG、PING画像を動作時にデコードする機能があります。ですが、この機能を多用すると、実行時のデコード処理がシステムの動作に悪影響を及ぼす場合がありますので使用する場合は注意が必要です。
まとめ
かなり簡略化した説明になりましたが、いかがでしたでしょうか。実際には細かな部分で様々な動作を行いますが、基本的には今回説明した動作を行います。
GUIXはイベントが起きたときのみ動作するように設計されたイベントドリブン型のGUIシステムなので、小さなシステムでも比較的導入がしやすいかと思います。
GUIXはThreadX上で動作することを前提に設計されていますが、弊社ではITRONシステムに導入した事例もあります。ご興味があれば気軽にお問い合わせください。