アプリケーションが拡張性のある一連のデータ型を管理する場合には、アクションの実行によりデータ型を直接実行しなければなりません。この章では、アプリケーションからアクションを実行する方法について説明します。アクションの実行方法を示すサンプル・プログラムも示します。
アクションとアクションの作成の詳細は、第 9 章「データ型データベースのアクセス」「データ型データベースのアクセス」と、『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の次の章を参照してください。
『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の「アクションとデータ型の概要」
『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の「アクション作成ツールを使ったアクションとデータ型の作成」
『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の「手入力によるアクションの作成」
『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の「手入力によるデータ型の作成」
デスクトップ・サービス・ライブラリによってエクスポートされたアクション実行 API は、アプリケーションから別のアプリケーションを実行したり、操作を実行したりするための方法の 1 つです。その他の方法として、次のものがあります。
fork/exec システム・コール
ToolTalk メッセージ
これらの方法は、それぞれ利点と制約があるので、具体的な状況を評価して、どちらが適切かを判断しなければなりません。
アクションは、従来のコマンド行アプリケーション (すなわち、COMMAND アクション) と ToolTalk アプリケーション (すなわち、TT_MSG アクション) の両方をカプセル化できます。アクションを実行するアプリケーションは、コマンドがフォークされたのか、それともメッセージが送られたのかを知る必要はありません。
アクションは多様性を持ち、デスクトップのデータ型機構と統合されます。これは、[開く] や [印刷] などのアクションは、与えられる引き数の型に基づいて異なる動作をするが、動作の違いは、アクションを呼び出すアプリケーションに対して透過されることです。
アクションは、アプリケーション開発者、システム統合者、システム管理者、およびエンドユーザに対して、構成の大きな可能性を提供します。これらのユーザは、アクション・データベースを編集して、アクションの実行方法の定義を変更できます。
アクションは、分散環境でも有効です。アプリケーションが fork/exec により別のアプリケーションを直接実行する場合には、両方のアプリケーションが同じシステム上で使用可能でなければならず、同じシステム上で実行可能でなければなりません。それに対して、アクション実行 API は、アクション・データベース内の情報に基づいて、どのシステム上で COMMAND アクションを実行するかを判断します。
アクションによって、デスクトップの動作と常に一貫性のあるアプリケーションの動作が可能になります。これは、デスクトップのコンポーネントがユーザのデータ・ファイルを操作するときに、アクションを使用することで対話するからです。
アクション実行 API の欠点は、戻り値機能が制限されている実行方法であり、実行されたアクション・ハンドラとの対話機能がないことです。これらの機能が必要な場合には、fork/exec/pipes を使用できます。ただし、共通デスクトップ環境 (CDE) で望ましいプロセス間通信の方法は、一般化されたクライアント/サーバ・パラダイムを持つ ToolTalk です。
実行について説明します。アプリケーションがいくつかの異なる形式 (テキストとグラフィック) のデータ・ファイルを管理すると仮定し、これらのファイルの編集と表示の手段をユーザに提供する必要があると仮定します。アクションを使用せずにこれを実現するには、次の方法の 1 つを使用することになります。
fork/exec を使用して、適切なエディタを起動し、ユーザがエディタの名前を指定するための何らかの方法 (環境変数など) を考えてください。このアプローチには次のような制約があります。
システム・コールによりサブプロセスを実行し、その結果のシグナルを監視する複雑なコードを書かなければなりません。
アプリケーションと同じシステム上で使用できるエディタが必要であり、システム管理者は、rsh などの機能を使用する複雑な構成を提供しなければなりません。
システム管理者とユーザは、アプリケーションの固有の構成モデルを学び、管理しなければなりません。
ToolTalk メッセージを使用して、編集や表示などの操作をデータに対して実行することを要求します。このアプローチには、すべてのデータ型に対して使用可能な ToolTalk 形式のエディタが必要であるという制約があります。
アクションによりこれを実現するには、バッファまたはデータ・ファイルに対して [開く] アクションを実行するだけです。アクション実行 API はアクション・データベースに基づいて、送信する適切なメッセージまたは実行するコマンドを判断し、一時ファイルの作成や削除、必要なシグナルの取り込みなどのすべての詳細を処理します。
アクションのアプリケーション・プログラム・インタフェース (API) は、どの種類のアクションに対しても機能します。デスクトップでのアクションの種類は、次のとおりです。
コマンド・アクション |
実行するコマンド行を指定します。 |
ToolTalk アクション |
送信する ToolTalk メッセージを指定します。メッセージは、適切なアプリケーションによって受信されます。 |
マップ・アクション |
特定の動作を定義する代わりに、別のアクションを参照します。 |
詳細は、『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の第 10 章「アクションとデータ型の概要」を参照してください。
アクション実行 API は、デスクトップ・サービス・ライブラリからエクスポートされて、次のような多数のタスクを実行する関数を提供します。
アクションおよびデータ型定義のデータベースを初期化し、読み込みます。アクションを実行するためには、その前にデータベースが読み込まれていなければなりません。
データベースに問い合わせます。指定されたアクション、アクションに関連付けられたアイコン・イメージ、ラベル、または記述が存在するかどうかを判断する関数があります。
アクションを実行します。アプリケーションは、ファイルまたはバッファ引き数をアクションに渡すことができます。
アクション・ステータスを受け取り、引き数を返すコールバックを登録します。
アクション・コマンド、関数、およびデータ形式の詳細は、次のマニュアル・ページを参照してください。
dtaction(1)
dtactionfile(4)
DtActionCallbackProc(3)
DtActionDescription(3)
DtActionExists(3)
DtActionIcon(3)
DtActionInvoke(3)
DtActionLabel(3)
DtActionQuit(3)
DtActionQuitType(3)
DtActionStUpCb(3)
dtexec(1)
この節では、簡単なサンプル・プログラム actions.c について説明します。actions.c の完全なリストは、この章の終わりにあります。
アプリケーションがアクションを実行するには、その前に、デスクトップ・サービス・ライブラリ (アクション実行 API を含む) を初期化して、アクションおよびデータ型定義のデータベースを読み込まなければなりません。
デスクトップ・サービス・ライブラリを初期化するには、DtInitialize() 関数を使用します。
DtInitialize(*display,widget,*name,*tool_class)
DtInitialize() は、デフォルトのイントリンシクス関数 XtAppContext を使用します。API は、アプリケーションが app_context を指定しなければならないときに使用する追加の関数 DtAppInitialize() を提供します。
DtAppInitialize(app_context,*display,widget,*name, tool_class)
次のコードの一部分は、サンプル・プログラム actions.c の中で DtInitialize() がどのように使用されているかを示しています。
if (DtInitialize(XtDisplay(shell), shell, argv[0],ApplicationClass)==False) { /* DtInitialize() has already logged an appropriate error msg */ exit(-1); }
アクションおよびデータ型データベースを読み込むには、DtDbLoad() 関数を使用します。
DtDbLoad(void)
DtDbLoad() は、アクションおよびデータ型データベースを読み込みます。この関数は、データベース・ファイルを検索するディレクトリのセット (データベース検索パス) を判断して、データベース内で見つかった *.dt ファイルを読み込みます。ディレクトリ検索パスは、DTDATABASESEARCHPATH 環境変数と内部のデフォルト値に基づきます。
長時間実行中のアプリケーションの中で DtDbLoad() を使用する場合、データベースが変更されたときには、動的に再読み込みしなければなりません。
DtDbReloadNotify() 関数を使用して、再読み込みイベントの通知を要求します。
/* Notice changes to the database without needing to restart application */ DtDbReloadNotify(DbReloadCallbackProc, callback_proc, XTPointer, client_data);
次の作業を実行するコールバックを指定します。
アプリケーションによって保持されている、キャッシュされたデータベース情報を破棄する。
DtDbLoad() 関数を再コールする。
callback_proc は、アプリケーションが保持している、キャッシュされたデータベース情報をクリーンアップしてから、DtDbLoad() を呼び出します。client_data を使用して、追加のクライアント情報をコールバック・ルーチンに渡すことができます。
アプリケーションは、アクションのアイコンまたはラベルを表示する必要がある場合には、データベースにアクセスします。また、アクションを実行することによって、アプリケーションはアクションの存在をチェックできます。データベース内のアクションは、アクション名によって識別されます。
ACTION action_name { … }
たとえば、[電卓] アクションの定義は次のとおりです。
ACTION Dtcalc { LABEL 電卓 ICON Dtcalc ARG_COUNT 0 TYPE COMMAND WINDOW_TYPE NO_STDIO EXEC_STRING /usr/dt/bin/dtcalc DESCRIPTION 電卓 (Dtcalc) アクションは、デスクトップ電卓 \ アプリケーションを起動します }
[電卓] アクションのアクション名は Dtcalc です。
実行形式ファイルがデータベース内のアクション名と一致するファイル名を持つ場合には、そのファイルはアクション・ファイルです。すなわち、基本のアクションの表現です。そのファイルのアイコンとラベルに関する情報は、データベースに格納されます。
指定されたアクション定義が存在するかどうかを判断するには、DtActionExists() 関数を使用します。
DtActionExists(*name)
DtActionExists() は、指定された名前がデータベース内のアクションの名前に一致するかどうかをチェックします。この関数は、名前がアクション名に一致する場合には True を返し、その名前のアクションが見つからない場合には False を返します。
アイコン・イメージ情報を取り出すには、DtActionIcon() 関数を使用します。
DtActionIcon(char *action_name)
アクション定義は、アクションを表すために使われるアイコン・イメージを定義の ICON フィールドで指定します。
ACTION action_name { ICON icon_image_base_name … }
DtActionIcon() は、アイコン・イメージ・フィールドの値にある文字列を返します。アクション定義にアイコン・フィールドがない場合には、この関数はデフォルトのアクション・アイコン・イメージの値 Dtactn を返します。
次に、使用したいアイコンとサイズの位置を決めます。アイコンには 4 つのサイズがあり、ビットマップまたはピックスマップ形式で使用できます。たとえば、[電卓] のアクション定義からアイコン・ファイルのベース名を見つけることができます。次に、そのベース名と表 8–1 の情報の組み合わせと、すべてのアイコンの格納情報から、目的のアイコン・ファイルを見つけ出せます。
[電卓] アクションのアイコン名は Dtcalc ですが、これはファイル名全体ではありません。アイコン・ファイル名はアイコンのサイズに基づき、4 つのサイズがあります。表 8–1 は、デスクトップ・アイコンのサイズとファイル名の命名規則を示します。
表 8–1 アイコンのサイズとファイル名
アイコンのサイズ |
ビットマップ名 |
ピックスマップ名 |
---|---|---|
16 × 16 (極小) |
name.t.bm |
name.t.pm |
24 × 24 (小) |
name.s.bm |
name.s.pm |
32 × 32 (中) |
name.m.bm |
name.m.pm |
48 × 48 (大) |
name.l.bm |
name.l.pm |
デスクトップ・アイコン・ファイルの詳細は、『Solaris 共通デスクトップ環境 上級ユーザ及びシステム管理者ガイド』の第 14 章「デスクトップのアイコンの作成」を参照してください。
ビットマップの場合、マスクとして使われる追加のファイルがあり、そのファイルの拡張子 _m.bm で終わります。したがって、各サイズのアイコンに対して合計 3 個のファイルがあります。次に、電卓のアイコン・ファイルを示します。
Dtcalc.t.bm Dtcalc.t.pm Dtcalc.t_m.bm Dtcalc.m.bm Dtcalc.m.pm Dtcalc.m_m.bm Dtcalc.l.bm Dtcalc.l.pm Dtcalc.l_m.bm
電卓には小型アイコン (Dtcalc.s.bm、Dtcalc.s.pm、Dtcalc.s_m.bm) がない点に注意してください。
DtActionIcon() はベース名だけを返します。電卓の場合は Dtcalc です。種類 (ピックスマップまたはビットマップ) とサイズ (極小、小、中、大) を選択して、適用可能な拡張子をベース名に追加してください。また、ファイルがどこにあるかを知っておいてください。
アクションのローカライズ・ラベルを取り出すには、DtActionLabel() 関数を使用します。
char *DtActionLabel(char *actionName)
アクション定義にはラベルを入れることができます。ラベルは、label_text フィールドを使用して定義されます。
ACTION action_name { LABEL label_text … }
このラベルは、グラフィック・コンポーネント (ファイル・マネージャやアプリケーション・マネージャなど) の中でアクションのアイコンにラベルを付けるために使用されます。アクション定義に label_text フィールドがない場合には、action_name が使用されます。
label_text 文字列の値は、エンドユーザがアクションを見分けられるように、すべてのインタフェース・コンポーネントによって使用されなければなりません。
DtActionLabel() 関数は、actionName という名前のアクションのアクション定義の中の label_text フィールドの値を返します。label_text フィールドがない場合には、この関数は actionName を返します。
アプリケーションがデスクトップ・サービス・ライブラリを初期化した後は、アクションを実行できます。
アクションを実行するには、DtActionInvoke() 関数を使用します。
DtActionInvoke (widget, action, args, argCount, termOpts, execHost, contexDir, useIndicator,statusUpdateCb, client_data)
DtActionInvoke() は、アクション・データベースから、指定されたアクション名に一致するエントリを探して、指定されたクラス、型、およびカウントの引き数を受け入れます。アクションを実行する前に、アプリケーションはデータベースを初期化し、読み込まなければならないので注意してください。
/* * (c) Copyright 1993, 1994 Hewlett-Packard Company * (c) Copyright 1993, 1994 International Business Machines Corp. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * (c) Copyright 1993, 1994 Novell, Inc. */ #include <Xm/XmAll.h> #include <Dt/Dt.h> #include <Dt/Action.h> #define ApplicationClass "Dtaction" static Widget shell; static XtAppContext appContext; static Widget actionText; static Widget fileText; static void CreateWidgets(Widget); static void InvokeActionCb(Widget, XtPointer, XtPointer); static void InvokeAction(char*, char*); static void DbReloadProc(XtPointer); void main(int argc, char **argv) { Arg args[20]; int n=0; int numArgs = 0; shell = XtAppInitialize(&appContext , ApplicationClass, NULL, 0, &argc, argv, NULL, args, n); CreateWidgets(shell); if (DtInitialize(XtDisplay(shell), shell, argv[0], ApplicationClass)==False) { /* DtInitialize() has already logged an appropriate error msg */ exit(-1); } /* Load the filetype/action databases */ DtDbLoad(); /* Notice changes to the database without needing to restart application */ DtDbReloadNotify(DbReloadProc, NULL); XtRealizeWidget(shell); XmProcessTraversal(actionText, XmTRAVERSE_CURRENT); XtAppMainLoop(appContext); } static void CreateWidgets(Widget shell) { Widget messageBox, workArea, w; Arg args[20]; int n; XmString labelString; labelString = XmStringCreateLocalized("Invoke"); n = 0; XtSetArg(args[n], XmNdialogType, XmDIALOG_TEMPLATE); n++; XtSetArg(args[n], XmNokLabelString, labelString); n++; messageBox = XmCreateMessageBox(shell, "messageBox", args, n); XtManageChild(messageBox); XmStringFree(labelString); XtAddCallback(messageBox, XmNokCallback, InvokeActionCb, NULL); n = 0; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n++; XtSetArg(args[n], XmNnumColumns, 2); n++; XtSetArg(args[n], XmNentryAlignment, XmALIGNMENT_END); n++; workArea = XmCreateWorkArea(messageBox, "workArea", args, n); XtManageChild(workArea); labelString = XmStringCreateLocalized("Invoke Action:"); n = 0; XtSetArg(args[n], XmNlabelString, labelString); n++; w = XmCreateLabel(workArea, "actionLabel", args, n); XtManageChild(w); XmStringFree(labelString); labelString = XmStringCreateLocalized("On File:"); n = 0; XtSetArg(args[n], XmNlabelString, labelString); n++; w = XmCreateLabel(workArea, "fileLabel", args, n); XtManageChild(w); XmStringFree(labelString); n = 0; XtSetArg(args[n], XmNcolumns, 12); n++; actionText = XmCreateTextField(workArea, "actionText", args, n); XtManageChild(actionText); n = 0; XtSetArg(args[n], XmNcolumns, 12); n++; fileText = XmCreateTextField(workArea, "fileText", args, n); XtManageChild(fileText); } static void DbReloadProc(XtPointer cd) { /* Pick up any dynamic changes to the database files */ DtDbLoad(); } static void InvokeActionCb(Widget w, XtPointer cd, XtPointer cb) { char *action; char *file; action = XmTextFieldGetString(actionText); if (action == NULL) return; if (strlen(action) == 0) { XtFree(action); return; } file = XmTextFieldGetString(fileText); InvokeAction(action, file); XtFree(action); XtFree(file); XmTextFieldSetString(actionText, ""); XmTextFieldSetString(fileText, ""); XmProcessTraversal(actionText, XmTRAVERSE_CURRENT); } static void InvokeAction(char *action, char *file) { DtActionArg *ap = NULL; int nap = 0; DtActionInvocationID actionId; /* If a file was specified, build the file argument list */ printf("%s(%s)\n",action,file); if (file != NULL && strlen(file) != 0) { ap = (DtActionArg*) XtCalloc(1, sizeof(DtActionArg)); ap[0].argClass = DtACTION_FILE; ap[0].u.file.name = file; nap = 1; } /* Invoke the specified action */ actionId = DtActionInvoke(shell,action,ap,nap, NULL,NULL,NULL,True,NULL,NULL); }