共通デスクトップ環境 Dtksh ユーザーズ・ガイド

第 3 章 上級トピック

前章までで 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 言語でプログラミングする場合、アプリケーションはハンドラ関数を提供します。この関数は、入力が可能な場合に呼び出されます。入力ソースからデータを読み込んだり、エスケープ文字や継続行を処理するのは、ハンドラの役割です。

dtkshXtAddInput 機能もサポートしますが、シェル・プログラマが簡単に使用できるようにします。デフォルトでは、シェル・スクリプトがファイル記述子の配信対象を登録する場合、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 イベント構造体によって定義されるサブフィールドが続いている) を使用してアクセスできます。

dtksh は、次のイベント型のすべてのイベント・フィールドへのアクセスをサポートします。

次の例は、前述のイベント型のサブフィールドへのアクセスの仕方を示しています。

${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 つのコマンドを使用して行われます。

ワークスペース管理を扱う特定の 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 を使用して 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>

描画関数、xororclearandcopynoopnornandsetinvertequivandReverseorReversecopyInverted などを指定します。

-line_style <style>

線の形状、LineSolidLineDoubleDash、または 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")'