# 上級トピック

これまでに、`dtksh`の基本的な知識について説明しました。この章は、より上級の トピックを説明します。

## コンテキスト変数の使用方法

`dtksh`は、アプリケーションの外見に対するコンテキストを提供する多くの変数が あります。

### イベント・ハンドラ・コンテキスト変数

アプリケーションは、指定したイベントの1つが発生したときに生じるアクションに対する ウィジェットのイベント・ハンドラを登録しています。アクションは、任意の`dtksh` コマンド行で指定できます。例えば、次のとおりです。

    XtAddEventHandler $W “Button2MotionMask“ false “ActivateProc“
    XtAddEventHandler $W “ButtonPressMask|ButtonReleaseMask“ \
          false “echo action“

イベント・ハンドラに対するコンテキストを提供するために、2つの環境変数が定義され ています。

EH_WIDGET | イベント・ハンドラを登録する ウィジェットのIDを設定します。
EH_EVENT | イベント・ハンドラを起動する`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 つの変数は、次のとおりです。

TRANSLATION_WIDGET | トランスレーションが登録されているウィジェットの ウィジェット操作を設定します。
TRANSLATION_EVENT | トランスレーションを起動する`XEvent`のアドレスを 設定します。

次のようなドット表記で、イベントのフィールドにアクセスできます。

    echo “Event type = “${TRANSLATION_EVENT.TYPE}
    echo “Display = “${TRANSLATION_EVENT.XANY.DISPLAY}

### ワークスペース・コールバック・コンテキスト変数

アプリケーションは、ユーザが新規ワークスペースに変更したとき、常に呼び出される コールバック関数を登録することができます。コールバックが呼び出されたとき、2つの 特別な環境変数を設定します。この環境変数は、シェル・コールバックのコードでアクセス できます。

CB_WIDGET | コールバックを呼び出すウィジェットのIDを設定します。
CB_CALL_DATA | 新規ワークスペースを一意に識別するXアトムを設定します。 これは、`XmGetAtomName`コマンドを使用して 文字表現に変換できます。

### 入力コンテキスト変数

Xtイントリンシクスは、`XtAddInput`機能を提供おり、 アプリケーションは、特定のファイル記述子から使用可能な任意なデータのアクセス手段を 登録できます。C言語でプログラミングしたとき、アプリケーションはハンドラ関数を 提供します。これは入力が可能なときに呼び出される関数です。 入力ソースからのデータの読み込み、エスケープ文字や継続行の操作は、ハンドラが行います。

`
dtksh`も、`XtAddInput`機能をサポートしていますが、それ以上の処理を行い、 シェル・プログラマから容易に使用できます。デフォルトでは、シェル・スクリプトが ファイル記述子のアクセス手段を登録したとき、`dtksh`は、テキストの完全行を受け取った場合にのみ、`dtksh`はシェル・スクリプトの 入力ハンドラを呼び出します。テキストの完全行は、エスケープされていない改行文字 またはファイルの終りのどちらかで終了した行と定義されます。入力ハンドラは、使用 可能なデータがなく、ファイルの終りに達した場合にも呼び出されます。ハンドラは、 入力ソースを削除し、ファイル記述子を閉じるのに、`
XtRemoveInput`を使用でき ます。このデフォルト動作の利点は、入力ハンドラがエスケープ処理または継続行の操作 を考慮する必要がないことです。欠点は、すべての入力が行単位で、バイナリ情報を 含んでいないことを想定している点です。

`dtksh`は、入力ソースがバイナリ情報を含んでいる場合、または入力ハンドラが入力 ソースから直接データを読み込みたい場合、„raw”
入力モードをしています。 rawモードでは、`dtksh`は入力ソースからデータを読み込めません。 `dtksh`は、 入力ソースに入力が可能なことを知らせるときに、シェル・スクリプトの 入力ハンドラを呼び出します。入力データを読み込んだり、バッファの要求とエスケープ 処理を行ったり、ファイルの終りになったかを検出したりするのは、ハンドラが行います。 (これにより、入力ソースを削除、ファイル拡張子を閉じることが できます)。このモードは、まれにしか`dtksh`スクリプトで必要となる ことはありません。

入力ハンドラが、デフォルト・モードまたはrawモードのどちらで動くように構成されているで、 `dtksh`はシェル・スクリプトの入力ハンドラを呼び出す前に、いくつかの 環境変数を設定します。これらの環境変数は、入力ハンドラに、入力データの操作に必要な もののすべてを提供します。

`INPUT_LINE` | デフォルト・モードのとき、この変数は入力ソースから使用可能な次の入力の完全行 になります。`INPUT_EOF`がtrueのときは、このバッファにデータがありません。rawモードのときはこの変数は常に空文字になります。
`INPUT_EOF` | デフォルト・モードのとき、この変数は、`INPUT_LINE`にデータが含まれて いるときはfalseが設定され、ファイルの終りに達したときにtrueが設定されます。 ファイルの終りに達したときに、シェル・スクリプトの入力ハンドラは入力ソースを 登録解除し、ファイル記述子を閉じます。rawモードで作動すると、この変数は常に falseが設定されます。
`INPUT_SOURCE` | これは、入力が可能なファイル記述子を示します。rawモードで作動すると、 このファイル記述子は、保留になっている入力を得るのに使用されます。 ファイル記述子は、必要がなくなったときに、入力ソースを閉じるのにも使用 されます。
`INPUT_ID` | これは、入力ソースが登録されているときに、`XtAddInput`が 返すIDを示します。この情報は、`XtRemoveInput`で入力ソースを削除する のに必要です。

## イベント・サブフィールドへのアクセス

`XEvent`構造体は、イベントの型に基づいて、異なる構成が多数あります。`dtksh`は、もっとも頻繁に 使用される`XEvents`へのアクセスのみ提供しています。他の標準的 な`XEvents`には、イベント型`XANY`を使用してアクセスします。 イベント型`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の 「組み込み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を使用したX描画関数へのアクセス

`dtksh`コマンドには、線、点、セグメント、区画、弧、および多角形を描く標準的な Xlib描画関数が含まれています。標準的なCプログラミングの環境において、これらの 関数は、描画データとしてだけではなく、引き数としてグラフィック・コンテキスト (GC)を見なしています。`dtksh`の描画関数では、GCオプションの 集合は、コマンドに対するパラメータ・リストで指定されます。

デフォルトでは、描画コマンドは特定のコマンドに使用された後に廃棄されるGCを 作成します。スクリプトが、`-gc`オプションを指定すると、 グラフィック・コンテキスト・オブジェクトの名前をコマンドに渡すことができます。 このGCはコマンドの解釈に使用され、変数は、コマンドが行うGCの変更によって更新 されます。

`-gc` <GC> | <GC>は、まだ初期化されていない環境変数、または前の描画コマンドの グラフィック・コンテキストを保持したままの環境変数の名前です。 このオプションが指定されたとき、初めにGCオプションを指定し なければなりません。
`-foreground` <color> | フォアグランドのカラーを指定します。 カラー名またはピクセル番号のどちらかで指定します。
`-background` <color> | バックグラウンドのカラーを指定します。 カラー名またはピクセル番号のどちらかで指定します。
`-font` <font name> | 使用するフォントの名前を指定します。
`-line_width` <number> | 描画中に使用する線の幅を指定します。
`-function` <drawing function | 描画関数を指定します。 `xor, or, clear, and, copy, noop, nor, nand, set, invert, equiv, andReverse, orReverse,`または`copyInverted` を指定できます。
`-line_style` <style> | 線の形状を指定します。 次の中から指定できます。 `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“)'