/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/* 
 * (c) Copyright 1997, The Open Group 
 */
/* 
 * (c) Copyright 1987, 1988, 1989, 1990, 1992, 1993 HEWLETT-PACKARD COMPANY 
 * ALL RIGHTS RESERVED 
*/

/*
 * Included Files:
 */
#include "WmGlobal.h"
#include "WmProtocol.h"
#include <Xm/XmAll.h>
#include <Dt/Dt.h>
#include <Dt/DtP.h>
#include <Dt/Action.h>
#include <Dt/WsmM.h>
#include <Dt/IndicatorM.h>
#include <Dt/UserMsg.h>
#include <Dt/Icon.h>

#include "WmBackdrop.h"
#include "WmError.h"
#include "WmFunction.h"
#include "WmWrkspace.h"
#include "WmIPC.h"
#include "WmXSMP.h"
#include "WmPanelP.h"
#include "DataBaseLoad.h"


/*
 * include extern functions and definitions
 */

extern void UpdateFileTypeControlFields ( void );
extern WmScreenData * GetScreenForWindow (Window);

static void ToolTalkError(Widget, char*, Tt_status);


/*
 *   data for the "DT screen"
 */


/*
 * globals
 */
Const char *szWM_TOOL_CLASS = DtWM_TOOL_CLASS;



/******************************<->*************************************
 *
 *  dtInitialize (char * program_name, XtAppContext appContext)
 *
 *  Description:
 *  -----------
 *  Initialize the messaging mechanism
 *
 *  Inputs:
 *  ------
 *  program_name - argv[0]
 *  appContext   - used throughout the WM
 *
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *
 ******************************<->***********************************/
void 
dtInitialize(
        char *program_name,
        XtAppContext appContext )
{
    
    (void) DtAppInitialize(appContext, DISPLAY1, wmGD.topLevelW1, 
				program_name, (char *)szWM_TOOL_CLASS);

    /* 
     * Load action definitions from the action database.
     */
#ifdef DT_PERFORMANCE
_DtPerfChkpntMsgSend("Begin action database load");
#endif

    DtDbLoad(); 

#ifdef DT_PERFORMANCE
_DtPerfChkpntMsgSend("End   action database load");
#endif

} /* END OF FUNCTION dtInitialize */

/******************************<->*************************************
 *
 *  dtInitializeMessaging (Widget)
 *
 *  Description:
 *  -----------
 *  Initialize the messaging mechanisms
 *
 *  Inputs:
 *  ------
 *
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *
 ******************************<->***********************************/

void
dtInitializeMessaging(Widget toplevel)
{
    int 		i;
    WmScreenData *	pSD;
    String		sName;

    Tt_status		status;
    Tt_pattern		notice_pattern, request_pattern;
    char		*default_session;

    int			fd;
    char		*procId;
    char		*errfmt;

    Tt_callback_action NoticeMsgCB(
	Tt_message m,
	Tt_pattern p);
    Tt_callback_action RequestMsgCB(
	Tt_message m,
	Tt_pattern p);

    /*
     * Makef sure we have a ToolTalk connection
     */
    procId = tt_open();
    status = tt_ptr_error(procId);
    if (status != TT_OK) {
        errfmt =
          GETMESSAGE(2, 2, "Could not connect to ToolTalk:\n%s\n");
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    fd = tt_fd();
    status = tt_int_error(fd);
    if (status == TT_OK) {
	XtAppAddInput(XtWidgetToApplicationContext(wmGD.topLevelW), fd,
		(XtPointer)XtInputReadMask, tttk_Xt_input_handler, procId);
    } else {
        ToolTalkError(toplevel, "tt_fd()", status);
    }


    default_session = tt_default_session();
    status = tt_ptr_error(default_session);
    if (status != TT_OK) {
        errfmt = GETMESSAGE(2, 4, "Could not get default ToolTalk session:\n%s\n");
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    errfmt = GETMESSAGE(2, 5, "Error constructing ToolTalk pattern:\n%s\n");
    notice_pattern = tt_pattern_create();
    status = tt_ptr_error(notice_pattern);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    request_pattern = tt_pattern_create();
    status = tt_ptr_error(request_pattern);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    status = tt_pattern_category_set(notice_pattern, TT_OBSERVE);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_category_set(request_pattern, TT_HANDLE);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_scope_add(notice_pattern, TT_SESSION);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_scope_add(request_pattern, TT_SESSION);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_session_add(notice_pattern, default_session);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_session_add(request_pattern, default_session);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    tt_free( default_session );
    status = tt_pattern_class_add(notice_pattern, TT_NOTICE);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_state_add(notice_pattern, TT_SENT);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_class_add(request_pattern, TT_REQUEST);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_state_add(request_pattern, TT_SENT);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }


    /*
     * Ops handled by the notice_pattern
     */
    status = tt_pattern_op_add(notice_pattern, "DtActivity_Beginning");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(notice_pattern, "DtActivity_Began");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(notice_pattern, "DtTypes_Reloaded");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    /*
     * Ops handled by the request_pattern
     */
    status = tt_pattern_op_add(request_pattern, "DtPanel_Restore");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(request_pattern, "DtWorkspace_SetCurrent");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(request_pattern, "DtWorkspace_Title_Set");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(request_pattern, "DtWorkspace_Add");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(request_pattern, "DtWorkspace_Delete");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_op_add(request_pattern, "GetWsmClients");
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    /*
     * Register callback for the notice_pattern
     */
    status = tt_pattern_callback_add(notice_pattern, NoticeMsgCB);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    /*
     * Register callback for the request_pattern
     */
    status = tt_pattern_callback_add(request_pattern, RequestMsgCB);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

    status = tt_pattern_register(notice_pattern);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }
    status = tt_pattern_register(request_pattern);
    if (status != TT_OK) {
        ToolTalkError(toplevel, errfmt, status);
	return;
    }

} /* END OF FUNCTION dtInitializeMessaging */


/******************************<->*************************************
 *
 *  dtCloseIPC ()
 *
 *  Description:
 *  -----------
 *  Shuts down the messaging mechanism
 *
 *  Inputs:
 *  ------
 *
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *  Should be done before exiting
 *
 ******************************<->***********************************/
void 
dtCloseIPC( void )
{
} /* END OF FUNCTION dtCloseIPC */



/******************************<->*************************************
 *  
 * void dtReadyNotification()
 *  
 *  Description:
 *  -----------
 *  Tells the world that we're up and ready.
 *
 *  Inputs:
 *  ------
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  --------
 *  Invoked as the fitting culmination of dtwm initialization
 *
 ******************************<->***********************************/
void 
dtReadyNotification( void )
{
    SendClientMsg( wmGD.dtSmWindow,
		  (long) wmGD.xa_DT_SM_WM_PROTOCOL,
		  (long) wmGD.xa_DT_WM_READY,
		  CurrentTime, NULL, 0);

} /* END OF FUNCTION dtReadyNotification */


/******************************<->*************************************
 *
 *  WmStopWaiting ()
 *
 *  Description:
 *  -----------
 *  This is called to turn off "system busy" activity
 *
 *  Inputs:
 *  ------
 * 
 *  Outputs:
 *  -------
 *  None
 *
 *  Comments:
 *  ---------
 *  This routine relies on two globals, blinkerPCW and dtSD,
 *  on the major assumptions that:
 *     - there is just one DT Screen, with the front panel enabled
 *     - there is just one dtwmbusy control in that front panel
 ******************************<->***********************************/
void 
WmStopWaiting( void )
{
     if (wmGD.dtSD)
     {
	 WmFrontPanelSetBusy (False);
     }
} /* END OF FUNCTION WmStopWaiting */



/******************************<->*************************************
 *
 *  dtSendWorkspaceModifyNotification ()
 *
 *  Description:
 *  -----------
 *  This is called to announce that the workspace set has been
 *  modified
 *
 *  Inputs:
 *  ------
 *  pSD		- pointer to screen data
 *  aWs		- id of workspace just modified
 *  iType	- type of modification
 * 
 *  Outputs:
 *  -------
 *  None
 *
 *  Comments:
 *  ---------
 *  Sends the message:
 *
 *    "MODIFY_WORKSPACE"  "<atom_for_wsname>" "<modify_type>"
 *
 *    <modify_type> is one of:
 *				ADD
 *				DELETE
 *				BACKDROP
 *				TITLE
 ******************************<->***********************************/
void
dtSendWorkspaceModifyNotification(
	WmScreenData *pSD,
	Atom aWs,
	int iType)
{
    char        sNum[40];
    char        pch[40];
    char        pchType[40];
    Tt_message  msg;
    Tt_status   status;

    msg = tt_pnotice_create(TT_SESSION, "DtWorkspace_Modified");
    status = tt_ptr_error(msg);
    if (status != TT_OK) {
        return;
    }
    sprintf(sNum, "%d", pSD->screen);
    status = tt_message_arg_add(msg, TT_IN, Tttk_string, sNum);
    if (status != TT_OK) {
        return;
    }
    sprintf (pch, "%ld", aWs);
    status = tt_message_arg_add(msg, TT_IN, Tttk_string, pch);
    if (status != TT_OK) {
        return;
    }
    sprintf (pchType, "%d", iType);
    status = tt_message_arg_add(msg, TT_IN, Tttk_string, pchType);
    if (status != TT_OK) {
        return;
    }
    status = tt_message_send(msg);
    if (status != TT_OK) {
        return;
    }
    tt_message_destroy(msg);
}


/******************************<->*************************************
 *
 *  dtSendMarqueeSelectionNotification ()
 *
 *  Description:
 *  -----------
 *  This is called to announce marquee selection state
 *
 *  Inputs:
 *  ------
 *  pSD		- pointer to screen data
 *  type	- id of workspace just modified
 *  x		- x position of UL corner of rectangle
 *  y		- y position of UL corner of rectangle
 *  width	- width of rectangle
 *  height	- height of rectangle
 * 
 *  Outputs:
 *  -------
 *  None
 *
 *  Comments:
 *  ---------
 *  Sends the message:
 *
 *    "MARQUEE_SELECTION"  "<type>" "<x>" "<y>" "<width>" "<height>"
 *
 *    <modify_type> is one of:
 *				BEGIN
 *				END
 *				CONTINUE
 *				CANCEL
 ******************************<->***********************************/
void
dtSendMarqueeSelectionNotification(
	WmScreenData *pSD,
	int	type,
	Position x,
	Position y,
	Dimension width,
	Dimension height)
{
    Tt_message  msg;
    Tt_status   status;
    char        sNum[40];

    msg = tt_pnotice_create(TT_SESSION, "DtMarquee_Selection");
    status = tt_ptr_error(msg);
    if (status != TT_OK) {
        return;
    }

    sprintf(sNum, "%d", pSD->screen);
    status = tt_message_arg_add(msg, TT_IN, Tttk_string, sNum);
    if (status != TT_OK) {
        return;
    }
    if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
	return;
    }
    if (tt_message_arg_ival_set(msg, 1, type) != TT_OK) {
	return;
    }
    if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
	return;
    }
    if (tt_message_arg_ival_set(msg, 2, x) != TT_OK) {
	return;
    }
    if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
	return;
    }
    if (tt_message_arg_ival_set(msg, 3, y) != TT_OK) {
	return;
    }
    if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
	return;
    }
    if (tt_message_arg_ival_set(msg, 4, width) != TT_OK) {
	return;
    }
    if (tt_message_arg_add(msg, TT_IN, "integer", NULL) != TT_OK) {
	return;
    }
    if (tt_message_arg_ival_set(msg, 5, height) != TT_OK) {
	return;
    }
    status = tt_message_send(msg);
    if (status != TT_OK) {
        return;
    }
    tt_message_destroy(msg);
}


/******************************<->*************************************
 *
 *  NoticeMsgCB ()
 *
 *
 *  Description:
 *  -----------
 *  This is called to handle busy and stopbusy message
 *
 *  Inputs:
 *  ------
 *  m = ToolTalk message
 *  p = ToolTalk pattern
 * 
 *  Outputs:
 *  -------
 *  TT_CALLBACK_PROCESSED
 *  TT_CALLBACK_CINTINUE
 *
 *  Comments:
 *  ---------
 ******************************<->***********************************/
Tt_callback_action
NoticeMsgCB(Tt_message m, Tt_pattern p)
{
    char	*op;
    Tt_status	status;

    if (tt_message_state(m) != TT_SENT) {
	return TT_CALLBACK_CONTINUE;
    }
    op = tt_message_op(m);
    status = tt_ptr_error(op);
    if (status != TT_OK) {
	return TT_CALLBACK_CONTINUE;
    }
    if (!strcmp(op, "DtActivity_Began")) {
	WmStopWaiting();

	/* CDExc21081 */
	tt_message_destroy(m);
    }
    else if (!strcmp(op, "DtActivity_Beginning")) {
	if (wmGD.dtSD) {
	   WmFrontPanelSetBusy (True);
	}

	/* CDExc21081 */
	tt_message_destroy(m);
    }
    else if (!strcmp(op, "DtTypes_Reloaded")) {
	/*
	 * Blink busy light during reload.
	 */
	WmFrontPanelSetBusy (True);

	/* 
	 * Load action definitions from the action database.
	 */
	DtDbLoad(); 

	UpdateFileTypeControlFields();

	/*
	 * Turn off busy light.
	 */
	WmFrontPanelSetBusy (False);

	/* CDExc21081 */
	tt_message_destroy(m);
    }

    tt_free(op);
    return TT_CALLBACK_PROCESSED;

} /* END OF FUNCTION NoticeMsgCB */


/******************************<->*************************************
 *
 *  RequestMsgCB ()
 *
 *
 *  Description:
 *  -----------
 *  This is called to handle busy and stopbusy message
 *
 *  Inputs:
 *  ------
 *  m = ToolTalk message
 *  p = ToolTalk pattern
 * 
 *  Outputs:
 *  -------
 *  TT_CALLBACK_PROCESSED
 *  TT_CALLBACK_CINTINUE
 *
 *  Comments:
 *  ---------
 ******************************<->***********************************/
Tt_callback_action
RequestMsgCB(Tt_message m, Tt_pattern p)
{
    char	*op;
    Tt_status	status;

    int			screen_num;
    WmScreenData	*pSD;
    WmWorkspaceData	*pWS = NULL;
    Atom		aWs;
    char		*pch;
    String		sName;

    if (tt_message_state(m) != TT_SENT) {
	return TT_CALLBACK_CONTINUE;
    }
    op = tt_message_op(m);
    status = tt_ptr_error(op);
    if (status != TT_OK) {
	return TT_CALLBACK_CONTINUE;
    }
    if (!strcmp(op, "DtPanel_Restore")) {
	tt_message_reply(m);
	tt_message_destroy(m);

	SessionDeleteAll();

	F_Restart( DTWM_REQP_NO_CONFIRM, NULL, NULL );
    }
    else if (!strcmp(op, "DtWorkspace_SetCurrent")) {
	/*
	 * 1st arg: integer, screen number
	 * 2nd arg: string, atom of workspace name
	 */

	/* get the first arg from the message */
	tt_message_arg_ival(m, 0, &screen_num);
	pSD = &wmGD.Screens[screen_num];

	/* get the second arg from the message */
	pch = tt_message_arg_val(m, 1);

	/* retrieve the selected workspace */
	aWs = strtoul (pch, (char **) NULL, 0);
	tt_free( pch );
	pWS = GetWorkspaceData (pSD, aWs);

	if (pWS) {
	    ChangeToWorkspace (pWS);
	}

	tt_message_reply(m);
	tt_message_destroy(m);
    }
    else if (!strcmp(op, "DtWorkspace_Title_Set")) {
	/*
	 * 1st arg: integer, screen number
	 * 2nd arg: string, atom of workspace name
	 * 3rd arg: string, new name for the workspace
	 */

	/* get the first arg from the message */
	tt_message_arg_ival(m, 0, &screen_num);
	pSD = &wmGD.Screens[screen_num];

	/* get the second arg from the message */
	pch = tt_message_arg_val(m, 1);

	/* retrieve the selected workspace */
	aWs = strtoul (pch, (char **) NULL, 0);
	tt_free( pch );
	pWS = GetWorkspaceData (pSD, aWs);

	/* get the third arg from the message */
	pch = tt_message_arg_val(m, 2);

	if (pWS) {
	    ChangeWorkspaceTitle (pWS, pch);
	}
	tt_free( pch );

	tt_message_reply(m);
	tt_message_destroy(m);
    }
    else if (!strcmp(op, "DtWorkspace_Add")) {
	/*
	 * 1st arg: string, user-visible title of the workspace
	 */
	pch = tt_message_arg_val(m, 0);

	F_CreateWorkspace( pch, NULL, NULL );
	tt_free( pch );

	tt_message_reply(m);
	tt_message_destroy(m);
    }
    else if (!strcmp(op, "DtWorkspace_Delete")) {
	/*
	 * 1st arg: string, atom of workspace name
	 */
	pch = tt_message_arg_val(m, 0);

	/* retrieve the selected workspace */
	aWs = strtoul (pch, (char **) NULL, 0);
	tt_free( pch );
	sName = (String) XmGetAtomName (DISPLAY1, aWs);

	F_DeleteWorkspace( sName, NULL, NULL );

	tt_message_reply(m);
	tt_message_destroy(m);

	XtFree(sName);
    }
    else if (!strcmp(op, "GetWsmClients")) {
	/* No TT_IN args. */
	ClientData **clients;
	int nClients;

	if (GetSmClientIdClientList(&clients, &nClients))
	{
	    char *clientIds = (char *)NULL;
	    int *clientWorkspaces = (int *)NULL;
	    int clientIdLen = 0;

	    SortClientListByWorkspace(clients, nClients);

	    tt_message_arg_ival_set(m, 0, nClients);
	    if (nClients > 0)
	    {
		int i;
		char *ptr;
		ClientData *pCD;

		clientIdLen = 0;
		for (i = 0; i < nClients; i++)
		    clientIdLen += strlen(clients[i]->smClientID) + 1;

		if (((clientIds =
		      (char *)XtMalloc(clientIdLen * sizeof(char)))
		     == (char *)NULL) ||
		    ((clientWorkspaces =
		      (int *)XtMalloc(nClients * sizeof(int)))
		     == (int *)NULL))
		{
		    if (clientIds != (char *)NULL)
			XtFree(clientIds);

		    /* LATER - Right way to handle errors? */
		    tt_message_fail(m);
		    tt_message_destroy(m);
		    tt_free(op);
		    return TT_CALLBACK_PROCESSED;
		}
		else
		{
		    for (i = 0, ptr = clientIds;
			 i < nClients;
			 ptr += strlen(pCD->smClientID) + 1, i++)
		    {
			pCD = clients[i];
			strcpy(ptr, pCD->smClientID);
			clientWorkspaces[i] =
			    pCD->pWsList[pCD->currentWsc].wsID;
		    }
		}
	    }
	    tt_message_arg_bval_set(m, 1, (unsigned char *)clientIds,
				    clientIdLen * sizeof(char));
	    tt_message_arg_bval_set(m, 2, (unsigned char *)clientWorkspaces,
				    nClients * sizeof(int));

	    if (clientIds != (char *)NULL)
		XtFree(clientIds);
	    if (clientWorkspaces != (int *)NULL)
		XtFree((char *)clientWorkspaces);
	    XtFree((char *)clients);
	}

	tt_message_reply(m);
	tt_message_destroy(m);
    } else {
	tt_free( op );
	return TT_CALLBACK_CONTINUE;
    }

    tt_free(op);
    return TT_CALLBACK_PROCESSED;

} /* END OF FUNCTION RequestMsgCB */



/******************************<->*************************************
 *
 *  ToolTalkError ()
 *
 *
 *  Description:
 *  -----------
 *
 *  Inputs:
 *  ------
 * 
 *  Outputs:
 *  -------
 *
 *  Comments:
 *  ---------
 ******************************<->***********************************/
#define GETXMSTRING(s, m, d)	XmStringCreateLocalized(GETMESSAGE(s,m,d))

static void
OKCB (Widget dialog, XtPointer client_data, XtPointer call_data)
{
    XtUnmanageChild((Widget) client_data);
}

static void
ToolTalkError(Widget parent, char *errfmt, Tt_status status)
{
    Arg		 args[10];
    Widget	 dialog, dialogShell;
    char	*errmsg, *statmsg, *title;
    XmString	 xms_errmsg, xms_ok, xms_title;
    int		 n;

    if (! tt_is_err(status)) return;

    statmsg = tt_status_message(status);
    errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
    sprintf(errmsg, errfmt, statmsg);

    xms_ok = GETXMSTRING(2, 3, "OK");
    xms_errmsg = XmStringCreateLocalized(errmsg);
    xms_title = GETXMSTRING(2, 1, "Dtwm - Error");

    n = 0;
    XtSetArg(args[n], XmNautoUnmanage, False); n++;
    XtSetArg(args[n], XmNokLabelString, xms_ok); n++;
    XtSetArg(args[n], XmNdialogTitle, xms_title); n++;
    XtSetArg(args[n], XmNmessageString, xms_errmsg); n++;
    XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;

    dialog = XmCreateErrorDialog(parent, "IconEditorError", args, n);
    XtAddCallback(dialog, XmNokCallback, OKCB, (XtPointer) dialog);
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));

    /*
     * Disable the frame menu from dialog since we don't want the user
     * to be able to close dialogs with the frame menu
     */
    dialogShell = XtParent(dialog);
    n = 0;
    XtSetArg(args[n], XmNmwmDecorations, MWM_DECOR_BORDER | MWM_DECOR_TITLE); n++;
    XtSetValues(dialogShell, args, n);
    XtManageChild(dialog);
    XtRealizeWidget(dialogShell);

    _DtSimpleError("Dtwm", DtFatalError, NULL, errmsg);

    XtFree(errmsg);
    XmStringFree(xms_ok);
    XmStringFree(xms_errmsg);
    XmStringFree(xms_title);
}
/****************************   eof    ***************************/
