前章までで dtksh に関する基本的な知識を学びました。この章では、より高度なトピックを紹介します。
dtksh には、アプリケーションのいろいろな状態に対するコンテキストを提供する数多くの変数があります。
アプリケーションは、指定したイベントの 1 つが発生した時に起こるアクションを指定するウィジェットにイベント・ハンドラを登録します。アクションには、任意の dtksh コマンド行を指定できます。たとえば、次のとおりです。
XtAddEventHandler $W "Button2MotionMask" false "ActivateProc"
XtAddEventHandler $W "ButtonPressMask|ButtonReleaseMask" ¥
false "echo action"
2 つの環境変数が、イベント・ハンドラへのコンテキストを提供するために次のように定義されます。
イベント・ハンドラが登録されるウィジェットの ID を設定します。
イベント・ハンドラを起動する XEvent のアドレスを設定します。
XEvent 構造体内のフィールドへのアクセスを次の例に示します。
if [ ${EH_EVENT.TYPE} = "ButtonPress" ]; then
echo "X = "${EH_EVENT.XBUTTON.X}
echo "Y= "${EH_EVENT.XBUTTON.Y}
elif [ ${EH_EVENT.TYPE} = "KeyPress" ]; then
echo "X = "${EH_EVENT.XKEY.X}
echo "Y = "${EH_EVENT.XKEY.Y}
fi
Xt イントリンシクスは、ウィジェットに対して登録されるイベントのトランスレーションを提供します。イベントのトランスレーション・コンテキストは、イベント・ハンドラの場合と同じ方法で提供されます。トランスレーション・コマンドで定義される 2 つの変数は次のとおりです。
トランスレーションが登録されるウィジェットのウィジェット・ハンドルを設定します。
トランスレーションを起動する XEvent のアドレスを設定します。
次のようなドット表記で、イベントのフィールドへアクセスします。
echo "Event type = "${TRANSLATION_EVENT.TYPE}
echo "Display ="${TRANSLATION_EVENT.XANY.DISPLAY}
アプリケーションは、ユーザが新規ワークスペースへ移動するたびに呼び出せるコールバック関数を登録できます。コールバックが呼び出されると、次に挙げる 2 つの特別な環境変数が設定され、これらはシェル・コールバック・コードによってアクセス可能です。
コールバックを呼び出すウィジェットの ID を設定します。
新規ワークスペースを一意に識別する X アトムを設定します。これは、XmGetAtomName コマンドを使用して文字列表現に変換できます。
Xt イントリンシクスは、XtAddInput 機能を提供します。これにより、アプリケーションは、特定のファイル記述子から利用可能なデータの配信対象を登録できます。C 言語でプログラミングする場合、アプリケーションはハンドラ関数を提供します。この関数は、入力が可能な場合に呼び出されます。入力ソースからデータを読み込んだり、エスケープ文字や継続行を処理するのは、ハンドラの役割です。
dtksh は XtAddInput 機能もサポートしますが、シェル・プログラマが簡単に使用できるようにします。デフォルトでは、シェル・スクリプトがファイル記述子の配信対象を登録する場合、dtksh は、テキストの絶対行を受け取った時のみシェル・スクリプトの入力ハンドラを呼び出します。テキストの絶対行は、エスケープされていない改行文字またはファイルの終わりによって終了している行と定義されます。入力ハンドラは、利用可能なデータが存在せず、ファイルの終わりに達した場合にも呼び出されます。この時、ハンドラは、XtRemoveInput を使用して入力ソースを削除し、ファイル記述子を閉じることができます。このデフォルト動作の利点は、入力ハンドラがエスケープ処理や継続行の処理にかかわらず動作する点です。不便な点は、すべての入力が行単位であり、バイナリ情報を含んでいないことを前提にしている点です。
dtksh はまた、入力ソースにバイナリ情報がある場合や、入力ハンドラがデータを入力ソースから直接読み込みたい場合に、「raw」 入力モードをサポートします。raw モードでは、dtksh は、入力ソースからデータを全く読み込みません。dtksh は入力が入力ソース上で行えるようになると、シェル・スクリプトの入力ハンドラを呼び出します。この時、入力データを読み込んだり、バッファリング要求やエスケープ処理を行なったり、いつファイルの終わりに到達したかを検出したりするのは、ハンドラの責任において行われます (これにより、入力ソースが削除され、ファイル記述子を閉じます)。dtksh スクリプトで、このモードが使用されることは、ほとんどありません。
入力ハンドラがデフォルト・モードまたは raw モードのどちらで作動するように構成されているかによって、シェル・スクリプトの入力ハンドラを呼び出す前に、dtksh がいくつかの環境変数を設定します。これらの環境変数は、入力データを処理するのに必要なすべてのものを入力ハンドラに提供します。その環境変数は次のとおりです。
デフォルト・モードで動作する場合、この変数には入力ソースで利用可能な次の完全入力行が格納されます。INPUT_EOF が true の場合、このバッファにはデータはありません。raw モードで作動する場合、この変数には常に空の文字列が格納されます。
デフォルト・モードで動作する場合、この変数は、INPUT_LINE にデータが格納されている限り false が設定され、ファイルの終わりに到達すると、true が設定されます。ファイルの終わりに到達すると、シェル・スクリプトの入力ハンドラは、入力ソースを登録解除し、ファイル記述子を閉じなければなりません。raw モードの場合、この変数は常に false が設定されます。
これは、入力が可能なファイル記述子を示します。raw モードで動作する場合、このファイル記述子は、保留になっている入力を獲得するために使用されます。ファイル記述子はまた、必要がなくなった時に入力ソースを閉じるためにも使用されます。
これは、入力ソースがすでに登録されている場合に XtAddInput が返す ID を示します。この情報は、XtRemoveInput で入力ソースを削除するのに必要です。
XEvent 構造体には、イベントの型に基づいて異なる構成が数多くあります。dtksh は、もっとも頻繁に使用される XEvents へのアクセスのみを提供します。他の標準的な XEvents へは、次のサブフィールドが含まれているイベント型 XANY (XANY イベント構造体によって定義されるサブフィールドが続いている) を使用してアクセスできます。
${TRANSLATION_EVENT.XANY.TYPE}
${TRANSLATION_EVENT.XANY.SERIAL}
${TRANSLATION_EVENT.XANY.SEND_EVENT}
${TRANSLATION_EVENT.XANY.DISPLAY}
${TRANSLATION_EVENT.XANY.WINDOW}
dtksh は、次のイベント型のすべてのイベント・フィールドへのアクセスをサポートします。
XANY
XBUTTON
XEXPOSE
XNOEXPOSE
XGRAPHICSEXPOSE
XKEY
XMOTION
次の例は、前述のイベント型のサブフィールドへのアクセスの仕方を示しています。
${TRANSLATION_EVENT.XBUTTON.X}
$(CB_CALL_DATA.EVENT.XKEY.STATE)
${EH_EVENT.XGRAPHICSEXPOSE.WIDTH}
ユーザがアプリケーションに対して [ウィンドウ・マネージャ] メニューで [閉じる] を選択した場合、アプリケーションが、クローズ通知を「取り込む」準備ができていないと終了してしまいます。アプリケーションが通知を取り込まないと、アプリケーションが管理する複数のウィンドウはすべて消え、アプリケーション・データは、望ましくない状態で残る場合があります。この状態を避けるために、dtksh を使用して、クローズ通知を受け取り処理できます。アプリケーションは、次のことを行わなければなりません。
クローズ通知を処理するプロシージャを定義する
[閉じる] が選択された場合に通知を要求する
アプリケーションをシャットダウンしないように応答を無効にする
次のコードは、この処理を説明しています。
# This is the `callback' invoked when the user selects
# the `Close' menu item
WMCallback()
{
echo "User has selected the Close menu item"
}
# Create the toplevel application shell
XtInitialize TOPLEVEL test Dtksh $0 "$@"
XtDisplay DISPLAY $TOPLEVEL
# Request notification when the user selects the `Close'
# menu item
XmInternAtom DELETE_ATOM $DISPLAY "WM_DELETE_WINDOW" false
XmAddWMProtocolCallback $TOPLEVEL $DELETE_ATOM "WMCallback"
# Ask Motif to not automatically close down your
# application window
XtSetValues $TOPLEVEL deleteResponse:DO_NOTHING
セッション・マネージャは、ユーザが現在のセッションを終了する時の状態をアプリケーションに保存させます。これによって、アプリケーションは、ユーザがセッションを再起動した時に、前回終了時の状態へ戻ることができます。
dtksh でこれを行うには、クローズ通知を処理する場合と同様の方法でハンドラを設定します。ハンドラを設定しないと、新規セッションでアプリケーションを手動で再起動しなければなりません。その場合、アプリケーションはいかなる状態も保持しません。
ハンドラを設定して現在の状態を保存するためには、アプリケーションで次のことを行います。
セッションの終わりの状態を保存し、起動時にそれを復元するための関数を定義する
セッション・マネージャの通知の配信対象を登録する
状態を保存する関数を登録する
起動時に、保存した状態を復元するか否かを決定する
次のコードは、この処理を説明しています。
#! /usr/dt/bin/dtksh
# Function invoked when the session is being ended by the user
SessionCallback()
{
# Get the name of the file into which we should save our
# session information
if DtSessionSavePath $TOPLEVEL PATH SAVEFILE; then
exec 9>$PATH
# Save off whether we are currently in an iconified state
if DtShellIsIconified $TOPLEVEL ; then
print -u9 `Iconified'
else
print -u9 `Deiconified'
fi
# Save off the list of workspaces we currently reside in
if DtWsmGetWorkspacesOccupied $(XtDisplay "-" $TOPLEVEL) ¥
$(XtWindow "-" $TOPLEVEL) ¥
CURRENT_WS_LIST ;
then
# Map the comma-separated list of atoms into
# their string representation
oldIFS=$IFS
IFS=","
for item in $CURRENT_WS_LIST;
do
XmGetAtomName NAME $(XtDisplay "-" $TOPLEVEL) ¥
$item
print -u9 $NAME
done
IFS=$oldIFS
fi
exec 9<&-
# Let the session manager know how to invoke us when
# the session is restored
DtSetStartupCommand $TOPLEVEL ¥
"/usr/dt/contrib/dtksh/SessionTest $SAVEFILE"
else
echo "DtSessionSavePath FAILED!!"
exit -3
fi
}
# Function invoked during a restore session; restores the
# application to its previous state
RestoreSession()
{
# Retrieve the path where our session file resides
if DtSessionRestorePath $TOPLEVEL PATH $1; then
exec 9<$PATH
read -u9 ICONIFY
# Extract and restore our iconified state
case $ICONIFY in
Iconified) DtSetIconifyHint $TOPLEVEL True;;
*) DtSetIconifyHint $TOPLEVEL False;
esac
# Extract the list of workspaces we belong in, convert
# them to atoms, and ask the Workspace Manager to relocate
# us to those workspaces
WS_LIST=""
while read -u9 NAME
do
XmInternAtom ATOM $(XtDisplay "-" $TOPLEVEL) ¥
$NAME False
if [ ${#WS_LIST} -gt 0 ]; then
WS_LIST=$WS_LIST,$ATOM
else
WS_LIST=$ATOM
fi
done
DtWsmSetWorkspacesOccupied $(XtDisplay "-" $TOPLEVEL) ¥
$(XtWindow "-" $TOPLEVEL) $WS_LIST
exec 9<&-
else
echo "DtSessionRestorePath FAILED!!"
exit -3
fi
}
################## Create the Main UI #######################
XtInitialize TOPLEVEL wmProtTest Dtksh $0 "$@"
XtCreateManagedWidget DA da XmDrawingArea $TOPLEVEL ¥
height:200 width:200
XmInternAtom SAVE_SESSION_ATOM $(XtDisplay "-" $TOPLEVEL) ¥
"WM_SAVE_YOURSELF" False
# If a command-line argument was supplied, then treat it as the
# name of the session file
if (( $# > 0))
then
# Restore to the state specified in the passed-in session file
XtSetValues $TOPLEVEL mappedWhenManaged:False
XtRealizeWidget $TOPLEVEL
XSync $(XtDisplay "-" $TOPLEVEL) False
RestoreSession $1
XtSetValues $TOPLEVEL mappedWhenManaged:True
XtPopup $TOPLEVEL GrabNone
else
# This is not a session restore, so come up in the default state
XtRealizeWidget $TOPLEVEL
XSync $(XtDisplay "-" $TOPLEVEL) False
fi
# Register the fact that we are interested in participating in
# session management
XmAddWMProtocols $TOPLEVEL $SAVE_SESSION_ATOM
XmAddWMProtocolCallback $TOPLEVEL $SAVE_SESSION_ATOM ¥
SessionCallback
XtMainLoop
dtksh は、Dt ライブラリの主要なワークスペース・マネージャ関数のすべてにアクセス可能です。たとえば、アプリケーションと関連のあるワークスペースのセットを問い合わせたり設定したりする関数、全ワークスペースのリストを問い合わせる関数、現在のワークスペースを問い合わせたり設定したりする関数、ユーザが別のワークスペースへ変更する時は常にアプリケーションに通知を要求する関数などです。
ユーザの側から見ると、ワークスペースは名前のセットで識別されますが、ワークスペース・マネージャの側から見ると、ワークスペースは X アトムで識別されます。シェル・スクリプトがワークスペース識別子のリストを要求すると、常に X アトムの文字列が返ります。複数の X アトムがある場合、リストはカンマで区切られます。ワークスペース・マネージャは、ワークスペース識別子を戻す場合と同じ形式をシェル・スクリプトが使用することを期待します。指定されたセッションの間のシェル・スクリプトによる X アトムの処理は安全です。そのセッション中に、X アトムの値が変わることはないからです。しかし、前節のセッション・マネージャのシェル・スクリプト例で示したように、シェル・スクリプトがワークスペース識別子の保存と復元を行う場合、保存する前に識別子を X アトム表現から文字列へ変換しなければなりません。また、セッションを復元する場合は、シェル・スクリプトは、情報をワークスペース・マネージャに渡す前に、名前を X アトムに再マッピングしなければなりません。X アトムと文字列間のマッピングと、文字列と X アトム間のマッピングは、次の 2 つのコマンドを使用して行われます。
XmInternAtom ATOM $DISPLAY $WORKSPACE_NAME false
XmGetAtomName NAME $DISPLAY $ATOM
ワークスペース管理を扱う特定の dtksh コマンドの詳細は、付録 A 「dtksh コマンド」 の「組み込み libDt セッション管理コマンド」で説明します。
dtksh スクリプトは、C アプリケーションに似たプロセスで、国際化対応とローカライズを行います。ユーザに表示されるすべての文字列は、スクリプト内で識別されます。ポストプロセッサは、スクリプトから文字列を抽出し、カタログを作成します。これは、要求されたロケールに翻訳できます。スクリプトを実行すると、現在のロケールは、表示文字列を捜すためのメッセージ・カタログを決定します。
文字列が表示される時、その文字列はセット内のメッセージ・セット ID (カタログに対応) とメッセージ番号で識別されます。これらの値は、ユーザに見えるテキストを決定します。次のコードで、そのプロセスを説明します。
# Attempt to open our message catalog catopen MSG_CAT_ID "myCatalog.cat" # The localized button label is in set 1, and is message # 2 XtCreatePushButton OK $PARENT ok ¥ labelString:$(catgets $MSG_CAT_ID 1 2 "OK") # The localized button label is in set 1, and is message #3 XtCreatePushButton CANCEL $PARENT cancel ¥ labelString:$(catgets $MSG_CAT_ID 1 3 "Cancel") # Close the message catalog, when no longer needed catclose $MSG_CAT_ID
catopen によって返されるファイル記述子は、kshell の exec コマンドではなく、catclose を使用して閉じなければならないことに注意してください。
dtksh コマンド群には、線、点、線分、矩形、弧、および多角形を描く標準的な Xlib 描画関数が含まれています。標準 C プログラミング環境では、これらの関数はグラフィックス・コンテキスト (GC) を描画データとしてだけではなく、引き数と見なします。dtksh の描画関数では、GC オプションの集合は、パラメータ・リスト内でコマンドに対して指定されます。
デフォルトでは、描画コマンドは、特定のコマンドに使用された後に捨てられる GC を作成します。スクリプトが -gc オプションを指定すると、グラフィックス・コンテキスト・オブジェクト名をコマンドへ渡すことができます。この GC は、コマンドの解釈に使用され、変数は、コマンドが行う GC の変更によって更新されます。
<GC> は、初期化されていないか、前の描画コマンドによるグラフィック・コンテキストを保持したままの環境変数名です。このオプションを指定する場合、まず GC オプションを指定しなければなりません。
カラー名またはピクセル番号で指定するフォアグラウンド・カラーです。
カラー名またはピクセル番号で指定するバックグラウンド・カラーです。
使用するフォント名を指定します。
描画中に使用する行の幅を指定します。
描画関数、xor、or、clear、and、copy、 noop、nor、nand、set、invert、 equiv、andReverse、orReverse、 copyInverted などを指定します。
線の形状、LineSolid、LineDoubleDash、または LineOnOffDash を指定します。
dtksh は、C プログラミング環境において、ウィジェット・トランスレーションを増加、無効、削除する機能を提供します。C では、アプリケーションは、トランスレーションのアクション・プロシージャのセットをインストールします。このセットは、特定のイベント・シーケンスに接続できます (トランスレーションは、イベント・シーケンスと関連アクション・プロシージャで構成されます)。dtksh 内のトランスレーションは、単一のアクション・プロシージャだけでも使用できる点を除いて、同様の方法で処理されます。ksh_eval と呼ばれるこのアクション・プロシージャは、渡されるパラメータを dtksh コマンドとして解釈し、トランスレーション開始時に評価します。次のシェル・スクリプトでは、トランスレーションの使用方法例を示しています。
BtnDownProcedure()
{
echo "Button Down event occurred in button "$1
}
XtCreateManagedWidget BUTTON1 button1 XmPushButton $PARENT ¥
labelString:"Button 1" ¥
translations:'#augment
<EnterNotify>:ksh_eval("echo Button1 entered")
<Btn1Down>:ksh_eval("BtnDownProcedure 1")'
XtCreateManagedWidget BUTTON2 button2 XmPushButton $PARENT ¥
labelString:"Button 2"
XtOverrideTranslations $BUTTON2 ¥
'#override
<Btn1Down>:ksh_eval("BtnDownProcedure 2")'