/*
 * Copyright 1991 - 1994,  Andrzej Stochniol, London, UK
 *
 * ASEDIT text editor, both binary and source (hereafter, Software) is
 * copyrighted by Andrzej Stochniol (hereafter, AS) and ownership remains
 * with AS.
 *
 * AS grants you (hereafter, Licensee) a license to use the Software
 * for academic, research and internal business purposes only, without a
 * fee.  Licensee may distribute the binary and source code (if released)
 * to third parties provided that the copyright notice and this statement
 * appears on all copies and that no charge is associated with such copies.
 *
 * Licensee may make derivative works.  However, if Licensee distributes
 * any derivative work based on or derived from the Software, then
 * Licensee will:
 * (1) notify AS regarding its distribution of the derivative work, and
 * (2) clearly notify users that such derivative work is a modified version
 *      and not the original ASEDIT distributed by AS.
 *
 * Any Licensee wishing to make commercial use of the Software should
 * contact AS to negotiate an appropriate license for such commercial use.
 * Commercial use includes:
 * (1) integration of all or part of the source code into a product for sale
 *     or license by or on behalf of Licensee to third parties, or 
 * (2) distribution of the binary code or source code to third parties that
 *     need it to utilize a commercial product sold or licensed by or on
 *     behalf of Licensee.
 *
 * A. STOCHNIOL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS
 * SOFTWARE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
 * IMPLIED WARRANTY.  IN NO EVENT SHALL A. STOCHNIOL BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * By using or copying this Software, Licensee agrees to abide by the
 * copyright law and all other applicable laws, and the terms of this
 * license.
 * AS shall have the right to terminate this license immediately by
 * written notice upon Licensee's breach of, or non-compliance with, any
 * of its terms.  Licensee may be held legally responsible for any
 * copyright infringement that is caused or encouraged by Licensee's
 * failure to abide by the terms of this license.
 *
 *
 * 	Andrzej Stochniol	(A.Stochniol@ic.ac.uk)
 * 	30 Hatch Road
 * 	London SW16 4PN
 * 	UK
 *
 *
 *      Telephone: +44 (0) 181-679 5795
 *      (work)Tel: +44 (0) 171-594 7076
 *            Fax: +44 (0) 171-584 1560
 *
 */

/*
 * asedit - Motif based internationalized editor
 *
 * Last changes: 01 November 1994
 *
 * asedit is a user friendly editor for X-Windows/Motif environment.
 * A Motif Text widget is used as a base for the editor.
 * Another text widget is used as a base for the hypertext system
 * (it is used there as emulation of a future (if any) help widget).
*/



#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Note: most of the corrections for vax11c (OpenVMS) are implemented thanks
   to Patrick L. Mahan (mahan@TGV.COM)
*/
#ifndef vax11c
#   include <fcntl.h>
#   include <unistd.h>	/* for unlink procedure */
#else
#   include <file.h>
#endif /* !vax11c */


#include <errno.h>
#include <sys/types.h>
#include <signal.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>

#include <Xm/Xm.h>
#include <Xm/CascadeB.h>
#include <Xm/DialogS.h>
#include <Xm/BulletinB.h>
#include <Xm/FileSB.h>
#include <Xm/MainW.h>
#include <Xm/MessageB.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/SelectioB.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/Text.h>
#include <Xm/Frame.h>
#include <Xm/PanedW.h>
#include <Xm/AtomMgr.h>	/* for XmInternAtom */

#include <Xm/TextP.h> 	/* needed for setting the tab size */

#if (XtSpecificationRelease > 3)
#   include <Xm/Protocols.h>	/* needed because of XmAddWMProtocolCallback;
				   available since X11R4 */
#   ifndef vax11c
#   	include <locale.h>	/* we support localization for X11R4 upwards */
#   endif  /* !vax11c */
#endif


#if (XtSpecificationRelease > 4)
#ifndef _NO_XMU
    /* include Xaw EditRes protocol ...(works OK since X11R5) */
#   include <X11/Xmu/Editres.h>
#endif
#endif

#if defined(vax11c) || defined(__DECC)
#   define unlink remove
#endif /* vax11c */


#include "asedit.h"
#include "version.h"
#include "machine.h"
#include "xresrc.h"

#if (XmVersion == 1000)
    /* conditional Motif 1.0 compilation **/
#   include "clipbrd.h"
#else
#   include  <Xm/CutPaste.h>    /* needed for registering clipboard format */

#endif


/*
  Widget and non-widget resources if the application defaults file can't be
  found.  Generated automatically from Asedit.ad by "ad2c".  Comment out the
  include line (but not the NULL) if you don't want any resources compiled
  in.
*/

#if (XmVersion > 1000)
    /* fallbackResources are only used from Motif 1.1  **/
    static String fallbackResources[] = {
#   if defined(vax11c) || defined(__DECC)
#     include "$A$sedit.ad$5nh"
#   else
#     include "Asedit.ad.h"
#   endif /* vax11c */
"*filter1:                      sed 's/^[       ]*$//' | sed '\\n\
/^$/ {\\n\
N\\n\
/^\\\\n$/D\\n\
     }'",				/* to work around bug in ad2c !!!!*/
"*appDefaultsVersion:    777",		/* to recognize a fallback case */
	NULL
    };

#endif  /* XmVersion ... */

#if (XmVersion >= 1002)
    static char motif1_2_id[] = "@(#)version for Motif 1.2";
#endif

/*****************************	Forward Declarations  ***********************/

/* I am commited to use ANSI compliant function prototypes. This is the proper
   way to handle function declarations and signatures (declaring the types of
   the parameters to the function). This convention is good style (and save
   a lot of debugging time!).

   Unfortunately there are still systems that do not support ANSI function
   prototypes. Because of that to make asedit portable to those systems I was
   forced to use conditional compilation. So, where appropriate I am using
   Motif based  #ifdef _NO_PROTO. It makes the code less readable, but there
   is really no other choice (sorry!).
*/
#ifdef _NO_PROTO	/* prototypes for non-ANSI systems follow ... */

static Widget CreateMenus ();
static void set_paste_buttons();
Boolean PrintString();
static void removeWinAndExit ();
static void ControlCloseCB();
static void save_yourself_proc();


extern void calc_text_lcn ();
extern void ResetAllMarks();
extern void executeFilterCmd();
extern void executeShellCmd();
extern void findDelimiterMate();
extern void show_moveLeft_dialog();
extern void show_moveRight_dialog();


# ifdef __hpux
    static int ByeBye();
# else
    static void ByeBye();
# endif /* __hpux */

#else  /* ! _NO_PROTO, ANSI prototypes follow */

static Widget CreateMenus (aseditWindowStruct *win, Widget parent);
static void set_paste_buttons();
Boolean PrintString(char *text_string, char *print_command);
static void removeWinAndExit (aseditWindowStruct *win);
static void ControlCloseCB(Widget w, XtPointer client_data, XtPointer call_data);
static void save_yourself_proc(Widget w, XtPointer client_data, XtPointer call_data);


extern void calc_text_lcn (Widget w, XtPointer client_data, XtPointer call_data);
extern void ResetAllMarks(aseditWindowStruct *win);
extern void executeFilterCmd(aseditWindowStruct *win, char *filterCmd,
			XmStringTable filterExt, Boolean needSelection);
extern void executeShellCmd(aseditWindowStruct *win, char *cmd, char *cmdInput,
		     int childOutDepot, char *dlgTitle,
		     XmTextPosition left, XmTextPosition right);
extern void findDelimiterMate(aseditWindowStruct *win, Boolean forward);
extern void show_moveLeft_dialog (aseditWindowStruct *win);
extern void show_moveRight_dialog (aseditWindowStruct *win);


# if defined(__STDC__) || defined(vax11c) || defined(__DECC)
    static void ByeBye(int sig);
# else
#   ifdef __hpux
      static int ByeBye(int sig, int code, struct sigcontext *scp, char *adr);
#   else
      static void ByeBye(int sig, int code, struct sigcontext *scp, char *adr);
#   endif  /* __hpux */
# endif /* __STDC__ || vax11c || __DECC */

#endif	/* end of conditional _NO_PROTO prototypes  compilation */


/* extra actions for edit text widgets */
extern XtActionsRec AseditExtraActionsTable[];	/* defined in srch_act.c */
extern Cardinal lenAseditExtraActionsTable;


/* minimum required version of the application defaults file */

#define  APP_DEFS_VERSION_REQUIRED 1320

/* all customizable definitions for menu structures are now (20.02.1993)
    defined as resources (i.e labelString, mnemonic, acceleratorText &
    accelerator); note slight name changes for menu items (Open <-- Open... etc.)
*/

static as_menuh_struct File_menu[] ={
	 {"New",      MenuCB, HelpCB, MENU_NEW,   	0, NULL},
	 {"Open",     MenuCB, HelpCB, MENU_OPEN,  	0, NULL},
	 {"Close",    MenuCB, HelpCB, MENU_CLOSE, 	0, NULL},
	 {NULL},				/* separator */
	 {"Save",     MenuCB, HelpCB, MENU_SAVE,  	0, NULL},
	 {"Save_As",  MenuCB, HelpCB, MENU_SAVE_AS, 	0, NULL},
	 {NULL},				/* separator */
	 {"Insert",    MenuCB, HelpCB, MENU_INSERT,   	0, NULL},
	 {"Print",    MenuCB, HelpCB, MENU_PRINT,   	0, NULL},
	 {NULL},				/* separator */
	 {"Exit",     MenuCB, HelpCB, MENU_EXIT,    	0, NULL},
	 };


static as_menuh_struct Edit_menu[] ={
	 {"Undo",     MenuCB, HelpCB, MENU_UNDO,	0, NULL},
	 {"Redo",     MenuCB, HelpCB, MENU_REDO,     	0, NULL},
	 {NULL},
	 {"Cut",      MenuCB, HelpCB, MENU_CUT,     	0, NULL},
	 {"Copy",     MenuCB, HelpCB, MENU_COPY,    	0, NULL},
	 {"Paste",    MenuCB, HelpCB, MENU_PASTE,   	0, NULL},
	 {NULL},					/* separator */
	 {"Clear",    MenuCB, HelpCB, MENU_CLEAR, 	0, NULL}
	 };


/**** remember that the following two submenus *MUST* have TOTAL_MARKS entries;
      (i.e. most probably 10, see asedit.h) 
***/

static as_menuh_struct Mark_menu_set[] ={
	 {"0",     MenuCB, HelpCB, MENU_MARK_SET0,  '0', 	NULL},
	 {"1",     MenuCB, HelpCB, MENU_MARK_SET1,  '1',   	NULL},
	 {"2",     MenuCB, HelpCB, MENU_MARK_SET2,  '2',  	NULL},
	 {"3",     MenuCB, HelpCB, MENU_MARK_SET3,  '3',  	NULL},
	 {"4",     MenuCB, HelpCB, MENU_MARK_SET4,  '4',  	NULL},
	 {"5",     MenuCB, HelpCB, MENU_MARK_SET5,  '5',  	NULL},
	 {"6",     MenuCB, HelpCB, MENU_MARK_SET6,  '6',  	NULL},
	 {"7",     MenuCB, HelpCB, MENU_MARK_SET7,  '7',  	NULL},
	 {"8",     MenuCB, HelpCB, MENU_MARK_SET8,  '8',  	NULL},
	 {"9",     MenuCB, HelpCB, MENU_MARK_SET9,  '9',  	NULL},
	};

static as_menuh_struct Mark_menu_go[] ={
	 {"0",     MenuCB, HelpCB, MENU_MARK_GO0,   '0', 	NULL},
	 {"1",     MenuCB, HelpCB, MENU_MARK_GO1,   '1',  	NULL},
	 {"2",     MenuCB, HelpCB, MENU_MARK_GO2,   '2', 	NULL},
	 {"3",     MenuCB, HelpCB, MENU_MARK_GO3,   '3', 	NULL},
	 {"4",     MenuCB, HelpCB, MENU_MARK_GO4,   '4', 	NULL},
	 {"5",     MenuCB, HelpCB, MENU_MARK_GO5,   '5', 	NULL},
	 {"6",     MenuCB, HelpCB, MENU_MARK_GO6,   '6', 	NULL},
	 {"7",     MenuCB, HelpCB, MENU_MARK_GO7,   '7', 	NULL},
	 {"8",     MenuCB, HelpCB, MENU_MARK_GO8,   '8', 	NULL},
	 {"9",     MenuCB, HelpCB, MENU_MARK_GO9,   '9', 	NULL},
	};

static as_menuh_struct Mark_menu[] ={
	 {"Set",    NULL, HelpCB, MENU_MARK_SET,0, NULL, NULL, Mark_menu_set,
		XtNumber(Mark_menu_set),	NULL},
	 {"Go_to",    NULL, HelpCB, MENU_MARK_GO,0, NULL, NULL, Mark_menu_go,
		XtNumber(Mark_menu_go),	NULL}
	};


static as_menuh_struct Match_menu[] ={
	 {"Forward",    MenuCB, HelpCB, MENU_MATCH_FORWARD, 0, NULL },
	 {"Backward",   MenuCB, HelpCB, MENU_MATCH_BACKWARD,0, NULL }
	};



static as_menuh_struct Search_menu[] ={
	 {"Find",     MenuCB, HelpCB, MENU_FIND,    	0, NULL},
	 {"Repeat",   MenuCB, HelpCB, MENU_FIND_NEXT,   0, NULL},
	 {"Change",   MenuCB, HelpCB, MENU_CHANGE, 	0, NULL},
	 {"Go_to",    MenuCB, HelpCB, MENU_GOTOLINE,	0, NULL,},
	 {NULL},					/* separator */
	 {"Mark",    NULL, HelpCB, MENU_MARK,0, NULL, NULL, Mark_menu,
		XtNumber(Mark_menu),	NULL} ,
	 {"Match",   NULL, HelpCB, MENU_MATCH, 0, NULL, NULL, Match_menu,
		XtNumber(Match_menu),   NULL},
	 };


static as_menuh_struct Filter_menu[] ={
	{"Extra", MenuCB, HelpCB, MENU_FILTER_EXTRA, 0, 	NULL},
	{"0", 	  MenuCB, HelpCB, MENU_FILTER_0,     0, 	NULL},
	{"1", 	  MenuCB, HelpCB, MENU_FILTER_1,     0, 	NULL},
	{"2", 	  MenuCB, HelpCB, MENU_FILTER_2,     0, 	NULL},
	{"3", 	  MenuCB, HelpCB, MENU_FILTER_3,     0, 	NULL},
	{"4", 	  MenuCB, HelpCB, MENU_FILTER_4,     0, 	NULL},
	{"5", 	  MenuCB, HelpCB, MENU_FILTER_5,     0, 	NULL},
	{"6", 	  MenuCB, HelpCB, MENU_FILTER_6,     0, 	NULL},
	{"7", 	  MenuCB, HelpCB, MENU_FILTER_7,     0, 	NULL},
	{"8", 	  MenuCB, HelpCB, MENU_FILTER_8,     0, 	NULL},
	{"9", 	  MenuCB, HelpCB, MENU_FILTER_9,     0, 	NULL},
	};

static as_menuh_struct Format_menu[] ={
	{"MoveLeft",    MenuCB, HelpCB, MENU_FORMAT_MOVE_LEFT, 		0, 	NULL},
	{"MoveRight",   MenuCB, HelpCB, MENU_FORMAT_MOVE_RIGHT,     	0, 	NULL},
	{"IndentWith",  MenuCB, HelpCB, MENU_FORMAT_INDENT_WITH,     	0, 	NULL},
	{"Reformat",    MenuCB, HelpCB, MENU_FORMAT_REFORMAT,  		0, 	NULL},
	 {NULL},			/* separator */
	 {"Expand",     MenuCB, HelpCB, MENU_EXPAND,     0, NULL},
	 {"Unexpand",   MenuCB, HelpCB, MENU_UNEXPAND,   0, NULL},
	};

static as_menuh_struct Case_menu[] ={
	{"Upper",  MenuCB, HelpCB, MENU_CASE_UPPER, 	0, 	NULL},
	{"Lower",  MenuCB, HelpCB, MENU_CASE_LOWER,     0, 	NULL},
	{"Title",  MenuCB, HelpCB, MENU_CASE_TITLE,     0, 	NULL},
	{"Toggle", MenuCB, HelpCB, MENU_CASE_TOGGLE,    0, 	NULL},
        };

static as_menuh_struct Command_menu[] ={
	{"Extra", MenuCB, HelpCB, MENU_COMMAND_EXTRA, 0, 	NULL},
	{"0", 	  MenuCB, HelpCB, MENU_COMMAND_0,     0, 	NULL},
	{"1", 	  MenuCB, HelpCB, MENU_COMMAND_1,     0, 	NULL},
	{"2", 	  MenuCB, HelpCB, MENU_COMMAND_2,     0, 	NULL},
	{"3", 	  MenuCB, HelpCB, MENU_COMMAND_3,     0, 	NULL},
	{"4", 	  MenuCB, HelpCB, MENU_COMMAND_4,     0, 	NULL},
	{"5", 	  MenuCB, HelpCB, MENU_COMMAND_5,     0, 	NULL},
	{"6", 	  MenuCB, HelpCB, MENU_COMMAND_6,     0, 	NULL},
	{"7", 	  MenuCB, HelpCB, MENU_COMMAND_7,     0, 	NULL},
	{"8", 	  MenuCB, HelpCB, MENU_COMMAND_8,     0, 	NULL},
	{"9", 	  MenuCB, HelpCB, MENU_COMMAND_9,     0, 	NULL},
	};

/* If you change the sequence or add some elements in Tools_menu
   check/edit some HACKS for Tools_menu (look for this string)
*/

static as_menuh_struct Tools_menu[] ={
	 {"Spell",     MenuCB, HelpCB, MENU_SPELL,        0, NULL},
	 {"Sort",      MenuCB, HelpCB, MENU_SORT,         0, NULL},
	 {NULL},			/* separator */
	 {"Format",    NULL, HelpCB, MENU_FORMAT,0, NULL, NULL, Format_menu,
		XtNumber(Format_menu),    NULL},
	 {"Case",    NULL, HelpCB, MENU_CASE,0, NULL, NULL, Case_menu,
		XtNumber(Case_menu),    NULL},
	 {NULL},			/* separator */
	 {"Filters",    NULL, HelpCB, MENU_FILTER,0, NULL, NULL, Filter_menu,
		XtNumber(Filter_menu),    NULL},
	 {"Commands",    NULL, HelpCB, MENU_COMMAND,0, NULL, NULL, Command_menu,
		XtNumber(Command_menu),    NULL},
	 };

	/* Note the ***HACK** of defining positions of Filters and Commands menus;
	   if you change the definition above make appropriate change below!!! */

#   define FILTERS_MENU_POS  6
#   define COMMANDS_MENU_POS 7

/* Describe the menu bar, giving only the names to appear in
 * the menu bar and pointers to each pulldown pane, already defined.
 */

static as_menuh_struct Main_menu[] ={
	 {"File",   NULL, HelpCB, MENU_FILE,    0, NULL, NULL, File_menu,
		XtNumber(File_menu),NULL},
	 {"Edit",   NULL, HelpCB, MENU_EDIT,    0, NULL, NULL, Edit_menu,
		XtNumber(Edit_menu),NULL},
	 {"Search", NULL, HelpCB, MENU_SEARCH,  0, NULL, NULL, Search_menu,
		XtNumber(Search_menu),NULL},


	 {"Tools", NULL, HelpCB, MENU_TOOLS,  0, NULL, NULL, Tools_menu,
		XtNumber(Tools_menu),NULL},


	 };


#define TOOLS_MENU_POS 	  3



/* Describe the structures for the help menu */

static as_menuh_struct Help_menu[] ={
	 {"On_Keys",	HelpCB, HelpCB, MENU_H_ON_KEYS,  	0, NULL},
	 {"Index", 	HelpCB, HelpCB, MENU_H_INDEX,     	0, NULL},
	 {"On_Help",    HelpCB, HelpCB, MENU_H_ON_HELP,    	0, NULL},
	 {NULL},			/* separator */
	 {"About",      MenuCB, HelpCB, MENU_H_ABOUT,	    	0, NULL}
	 };

/* Describe the Help button in the menu bar */

static as_menuh_struct help_Main_menu[] ={
	 {"Help",   NULL, HelpCB, MENU_HELP,  0, NULL, NULL, Help_menu,
		XtNumber(Help_menu),NULL}
	 };

/* popup menu */

static as_menuh_struct Qaccess_popup[] ={
	 {"Undo",     MenuCB, HelpCB, MENU_UNDO,        0, NULL},
	 {NULL},
	 {"Cut",      MenuCB, HelpCB, MENU_CUT,         0, NULL},
	 {"Copy",     MenuCB, HelpCB, MENU_COPY,        0, NULL},
         {"Paste",    MenuCB, HelpCB, MENU_PASTE,       0, NULL},
#ifdef USE_FIND_NEXT_IN_QACCESS
         {NULL},                                        /* separator */
         {"Repeat",   MenuCB, HelpCB, MENU_FIND_NEXT,   0, NULL},
#endif
         {NULL},                                        /* separator */
         {"Open",     MenuCB, HelpCB, MENU_OPEN,        0, NULL},
         {"Save",     MenuCB, HelpCB, MENU_SAVE,        0, NULL},
         {NULL},                                /* separator */
         {"Exit",     MenuCB, HelpCB, MENU_EXIT,        0, NULL},

         };

static as_menuh_struct Popup_list[] ={
         {"QAccess",   NULL, HelpCB, MENU_QACCESS,    0, NULL, NULL, Qaccess_popup,
                XtNumber(Qaccess_popup),NULL},
	};

Display		*display;	/*  Display		*/
Widget toplevel;		/* application shell (top level) (such a name
				   is used inside the clipboard functions ! )*/
Widget help_dialog = NULL;		/* global help for all asedit windows */

int    aseditWinCount = 0;		/* global count of active windows */

aseditWindowStruct *asedit_last_window = NULL;	/* the last asedit win structure in the chain */

/* all widget declarations moved to asedit.h ....(for version >= 1.2) */


static char *asedit_class 	= "Asedit";
static char *asedit_emacs_class = "Asedit_em";

char *PROGRAM_CLASS = NULL;
				/* PROGRAM_CLASS should be declared as 
					const char * 
				    but SUN does not recognize const
				    declaration yet !!!
				 */
char   *PROGRAM_NAME;		/* will be assigned from the command line */

Boolean	clipboard_filled=False; 	/* to show if there is something
					   in clipbboard to paste from */

Pixel	text_edit_background;	/* background colour of the main text widget
				   ( it is the colour of a recessed widget) */
Pixel   text_read_only_background;	/* a lighter colour to show that the file
					   is read only */
Pixel	select_menu_background;	/* background for editable widgets pop down
				   from the menus; it is equal to the menu buttons
				   arm colour */
Pixmap	xm_question_mark;	/* Motif question mark pixmap (initialized in
				   install_as_images) */
Pixmap	xm_excl_mark;		/* Motif exclamation mark pixmap; used since 1.27 to allow
				   using of SGI "buffy" pixmaps */

XmFontList default_fontlist;	/* default font list for the edit text widget */


#if (XmVersion >= 1002)		/* use new international Motif fontlist default */
XmStringCharSet charset = (XmStringCharSet) XmFONTLIST_DEFAULT_TAG;
#else
XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
				/* used to set up XmStrings */
#endif


XtAppContext app_context;	/* application context */

as_lstr		lstr;		/* language dependent messages */


/* temp hack */
/* three strings exported to ht_help .... */
String help_err_fopen, help_err_finc, help_no_info;





/*****************************  main  ***************************************
**
*/
#ifdef _NO_PROTO
int  main (argc, argv)
	unsigned int argc;
	char *argv[];
#else  /* ! _NO_PROTO */

int main (unsigned int argc, char *argv[])
#endif
{

    Arg			al[10];		/*  arg list		*/
    register int	ac;		/*  arg count		*/
    Boolean		set_signals = False;	/***!!!!!should be False; **/
    Atom		clipboard_atom;		/* to check if we have something in the clipboard */
    Boolean 		view_only_cmd_option = False;

    /* Ignore signals for now, but record whether they were already
       ignored or not so we can catch them later if need be.
    */
    if (
#ifdef SIGQUIT		/* not all systems define that (HP-UX does not) */
	(signal(SIGQUIT, SIG_IGN) != SIG_IGN) &&
#endif
	(signal(SIGINT,  SIG_IGN) != SIG_IGN))	set_signals = True;


    /* 	Get application name (note a special version for OpenVMS first)	*/
#if defined(vax11c) || defined(__DECC)
    if (( PROGRAM_NAME = strrchr(argv[0], (int) ']')) == NULL)
               PROGRAM_NAME = argv[0];
    else 
    {
               register char *ep;

               PROGRAM_NAME++;
               ep = strrchr(PROGRAM_NAME, '.');
               if (ep) *ep = '\0';
    }
#else
    if (( PROGRAM_NAME = strrchr(argv[0], (int) '/')) == NULL)
		PROGRAM_NAME = argv[0];
    else
		PROGRAM_NAME++;
#endif /* vax11c */

    PROGRAM_CLASS = asedit_class; 

    /* check the  command line for "-emacs" and "-em"  switches; */

    if(checkCommandForOption(argc, argv, "-emacs"))
    			PROGRAM_CLASS = asedit_emacs_class; 	/* use "emacs" class name */
    if(checkCommandForOption(argc, argv, "-em"))
    			PROGRAM_CLASS = asedit_emacs_class; 	/* use "emacs" class name */

    if(checkCommandForOption(argc, argv, "-v"))
    			view_only_cmd_option = True; 	/* view only mode requested on the command line */



    /*	Initialize toolkit and open display (!!! version dependent).	*/

    /* first set some special arguments for the toplevel shell (common for X11R3/4/5) */
    ac = 0;
    XtSetArg(al[ac], XmNmappedWhenManaged, False);	ac++;
    /* to AVOID:  "Error: Shell widget asedit has zero width and/or height"  set width & height explicitly */
    XtSetArg(al[ac], XmNwidth, 100);		ac++;
    XtSetArg(al[ac], XmNheight, 50);		ac++;

#if (XtSpecificationRelease  == 3)
    XtToolkitInitialize ();
    app_context = XtCreateApplicationContext();

    display = XtOpenDisplay (app_context, NULL, PROGRAM_NAME, PROGRAM_CLASS,
			cline_options, XtNumber(cline_options), &argc, argv);
    if (!display)
    {
	XtWarning ("can't open display, exiting...");
	exit (1);
    }
    /*	Create ApplicationShell.	*/
    toplevel = XtAppCreateShell (PROGRAM_NAME, PROGRAM_CLASS,
			applicationShellWidgetClass, display, al, ac);

#elif (XtSpecificationRelease > 4)

    /* initialize locale ... */
    XtSetLanguageProc(NULL, NULL, NULL);
    /***XtSetLanguageProc(NULL, _AsLanguageProc, NULL); ****/

    /*  there is a subtle difference in declaration of XtAppInitialize in X11R4
	and in X11R5; in X11R4 argc_in_out is declared as Cardinal* (i.e. in
	practice unsigned int*) but in X11R5 it is declared as int *  !!!
	So to avoid messages when prototypes are used we have to differentiate
	this situation (I hate small "improvements")
    */

#if (XmVersion >= 1002)
/****	XmRepTypeInstallTearOffModelConverter(); ***/
#endif 

    toplevel = XtAppInitialize(&app_context, (String)PROGRAM_CLASS,
			cline_options, XtNumber(cline_options), 
			(int *)&argc, argv, fallbackResources, al, ac);
    display = XtDisplay(toplevel);

#elif (XtSpecificationRelease == 4)	/* ... X11R4 version .... */
    /* initialize locale with the standard setlocale function */
#ifndef vax11c
    setlocale(LC_ALL,"");
#endif /* !vax11c */

    toplevel = XtAppInitialize(&app_context, (String)PROGRAM_CLASS,
			cline_options, XtNumber(cline_options),
			 (unsigned *)&argc, argv, fallbackResources, al, ac);
    display = XtDisplay(toplevel);

    /* we don't have to check for a valid display because it is done in
       XtAppInitialize (on error a message "Error: Can't Open Display" is shown )
    */
#endif


#if (XtSpecificationRelease > 4)
    /* addition of the X11R5 editres protocol */
#ifndef _NO_XMU
    XtAddEventHandler(toplevel, (EventMask)0, True, _XEditResCheckMessages, NULL);
#endif
#endif

    /* register TEXT format .... */
    XmClipboardRegisterFormat(display, "TEXT", (unsigned long)8);

    /* If we need to handle keyboard signals, do it now */
    if (set_signals)
    {
#ifdef SIGQUIT
	signal(SIGQUIT, ByeBye);
#endif
	signal(SIGINT, ByeBye);
    }

    /* always handle the following */
    signal(SIGTERM, ByeBye);
    signal(SIGHUP,  ByeBye);


    /* add asedit extra actions;
       the following should be before the first widget that may use
       our extra actions is created but after the toolkit initialization
    */
    XtAppAddActions(app_context, AseditExtraActionsTable, lenAseditExtraActionsTable);


    /* Get application resources (here: language strings) */
    XtGetApplicationResources(toplevel, (XtPointer)&lstr, resources,
				XtNumber(resources), NULL, 0);

    /* check the syntax of the command line (if all command
       switches were properly processed);
       if not show the syntax error message and exit
    */
    if(argc >1 && checkSyntax(argc, argv, PROGRAM_NAME, lstr.wrong_syntax, (char *)lstr.syntax))
    {
	XCloseDisplay(display);
	exit (1);                   /* exit this program */
    }

    /* check the version of the application default file; if old just print simple
       message
    */

    if(lstr.appDefaultsVersion <= 0 ) fprintf(stderr, lstr.noAppDefs);
    else if(lstr.appDefaultsVersion == 777) fprintf(stderr, lstr.fallAppDefs);
    else if(lstr.appDefaultsVersion < APP_DEFS_VERSION_REQUIRED) fprintf(stderr, lstr.oldAppDefs);


    /* set pointers to three strings  exported to ht_help .... */
    help_err_fopen = lstr.help_err_fopen;
    help_err_finc  = lstr.help_err_finc;
    help_no_info   = lstr.help_no_info;


    next_window(NULL);

    /* The creation of help_dialog is postponed (since asedit 1.2x) until
       the dialog is needed (see HelpCB)
    */

    /*	Realize toplevel widgets.	*/
    XtRealizeWidget (toplevel);


    /* now check if the desktop clipboard is filled ...
       if yes enable paste button !!!
    */
    clipboard_atom = XmInternAtom(display, "CLIPBOARD", False);
    if(XGetSelectionOwner(display, clipboard_atom)) 
    {
	/* the clipboard is filled ..... */
	clipboard_filled = True;
    }


    /* if a file name was specified in the command line open it */
    if(argc > 1)
    {   /* assume that the specified parameter is a filename */
	int i, n;
	n= argc;
	if(n > 10) n= 10;	/* make a maximum 10 windows */
	for(i=1; i<n; i++)
	{
	    if(i > 1) next_window(asedit_last_window);	/* create next window */
	    if(view_only_cmd_option) asedit_last_window->file_read_only = True;
	    open_file_in_last_window(argv[i]);
	    if((int) lstr.startLine > 0)
		go_to_line(asedit_last_window,(int) lstr.startLine, True);
	}


    }
    else
    {
	/* use the default name .... */
	open_file_in_last_window(NULL);
    }

    /*	Process events 	*/

    XtAppMainLoop(app_context);

}   /* main */


#ifdef _NO_PROTO
static Boolean textSelected (win)
    aseditWindowStruct *win;
#else  /* ! _NO_PROTO */
static Boolean textSelected (aseditWindowStruct *win)
#endif
{
    /* check if a non-zero length text is selected */
    Boolean selected;
    char *txt= NULL;
    XmTextPosition left, right;

    /* quick variant without memory allocation */
    selected = False;
    if(XmTextGetSelectionPosition(win->edit_text, &left, &right))
    {
	/* widgets owns the primary selection, check now if it isn't empty */
	if(left != right) selected = True;
    }


    return selected;

}   /* textSelected */

#ifdef _NO_PROTO
static void repeatOrSelectionFind (win)
    aseditWindowStruct *win;
#else  /* ! _NO_PROTO */
static void repeatOrSelectionFind (aseditWindowStruct *win)
#endif
{
    Boolean stext_selected= False;
    char *txt= NULL;

    /* since 1.3 either the last find action is repeated
       or if a text is selected (must not include a new line)
       a search for the text is carried out
     */

    if(win->weOwnPrimarySelection)	/* to speed the things up */
    {
	XmTextPosition left, right;
	int 	i, len;

	/* the text might be selected; get only selections that
	   are shorter than 100 chars (I hope that nobody is going
	   to search for longer strings; if not it is insane);
	   as a search pattern accept only text without embedded
	   newline;
	*/

	stext_selected = False;
	if(XmTextGetSelectionPosition(win->edit_text, &left, &right))
	{
	    /* the widget owns the primary selection, check now if it isn't empty
	       and that is not to long (must be shorter than 100) */
	
	    if( (left != right) && (left +100L > right) )
	    {
		/* get the selection */
		txt = XmTextGetSelection(win->edit_text);
		if(txt && (len = strlen(txt)) > 0)
		{
		    stext_selected = True;
		    /* check for the newline character */
		    for(i=0; i<len; i++)
		    {
			if(txt[i] == '\n')
			{
			    stext_selected = False;
			    break;
			}
		    }
		    if(!stext_selected && txt) XtFree(txt);
		}
	    }
	}
    }
    if(stext_selected)   /* use as a search string the selected one */
    {
	if(win->search_string)  XtFree(win->search_string);
	win->search_string = txt;
    }

    /* search for the string if set, otherwise let the user know
       what to do if the search_string is not set */

    if(win->search_string && (strlen(win->search_string) > (size_t)0))
    {
	find_string(win, True);
    }
    else
    {
	show_error_message(win, (char *) lstr.sm_have_to_select);
	win->found_string_start_pos = -1L;      /* to avoid continuing the
						   replace action (might not need it here) */
    }

}   /* repeatOrSelectionFind */


/*****************************  MapEditCB  *************************************
**
**      Process map and unmap callbacks for edit pulldown menu.
*/
#ifdef _NO_PROTO
void MapEditCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void MapEditCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
{
    XmRowColumnCallbackStruct *rcb_data =
			 (XmRowColumnCallbackStruct *) call_data;
    int    reason;              /* reason for the callback */

    int id                  = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);


    reason = rcb_data->reason;


    switch(reason)
    {
	case XmCR_MAP:
	    if(textSelected(win))
	    {
		if(!win->file_read_only)
		{
		    XtSetSensitive(win->menu_cut_button,   True);
		    XtSetSensitive(win->menu_clear_button,   True);
		}
		else
		{
		    XtSetSensitive(win->menu_cut_button,   False);
		    XtSetSensitive(win->menu_clear_button,   False);
		}
		XtSetSensitive(win->menu_copy_button,  True);
	    }
	    else
	    {
		XtSetSensitive(win->menu_cut_button,   False);
		XtSetSensitive(win->menu_copy_button,  False);
		XtSetSensitive(win->menu_clear_button, False);
	    }

	    /* check also if some other application did not filled up Clipboard (and that
	       was empty before that call)
	     */
	    if(!clipboard_filled)
	    {
		Atom      clipboard_atom = XmInternAtom(display, "CLIPBOARD", False);
		if(XGetSelectionOwner(display, clipboard_atom))
		{
		    set_paste_buttons();  /* set sensitivity of all paste buttons */
			clipboard_filled = True;
		}
	    }
	    break;

	case XmCR_UNMAP:
	    if(win->weOwnPrimarySelection)
	    {
	       if(!win->file_read_only)
	       {
		   XtSetSensitive(win->menu_cut_button,   True);
		   XtSetSensitive(win->menu_clear_button, True);
	       }
	       else
	       {
		   XtSetSensitive(win->menu_cut_button,   False);
		   XtSetSensitive(win->menu_clear_button, False);
	       }
	       XtSetSensitive(win->menu_copy_button,  True);
	    }
	    break;

	default:
	    /* an unknown client_data was received and there is no setup to handle this */
	    fprintf(stderr, "Warning: an unknown reason in MapEditCB callback\n");
	    break;

    }


}   /* MapEditCB */

/*****************************  MapToolsCB  *************************************
**
**      Process map and unmap callbacks for Tools pulldown menu.
*/
#ifdef _NO_PROTO
void MapToolsCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void MapToolsCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
{
    XmRowColumnCallbackStruct *rcb_data =
			 (XmRowColumnCallbackStruct *) call_data;
    int    reason;              /* reason for the callback */

    int id                  = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);
    int i;


    reason = rcb_data->reason;


    switch(reason)
    {
	case XmCR_MAP:
	    if(textSelected(win))
	    {
		/* turn on sensitivity of all tools buttons that need selection */
		for (i=0; i < win->nToolsSelNeeded; i++)
			XtSetSensitive(win->toolsSelNeeded[i], True);
	    }
	    else
	    {
		/* turn off sensitivity of all tools buttons that need selection */
		for (i=0; i < win->nToolsSelNeeded; i++)
			XtSetSensitive(win->toolsSelNeeded[i], False);
	    }
	    break;


	case XmCR_UNMAP:
	    if(win->weOwnPrimarySelection)
	    {
		for (i=0; i < win->nToolsSelNeeded; i++)
			XtSetSensitive(win->toolsSelNeeded[i], True);
	    }
	    break;

	default:
	    /* an unknown client_data was received and there is no setup to handle this */
	    fprintf(stderr, "Warning: an unknown reason in MapToolsCB callback\n");
	    break;

    }


}   /* MapToolsCB */





#ifdef _NO_PROTO
static Boolean setTabSize(w, tabsize)
    Widget w;
    int    tabsize;
#else  /* _NO_PROTO */

static Boolean setTabSize(Widget w, int tabsize)
#endif
{
    /* set the tab size for a text widget - returns True when successful */
    /* Note that this is a hack: we use some non-documented internal
       Motif data for the text output; watch out for Motif 2.0 !!
       Be sure that tabsize is > 0 !
    */
    /* do the following only when the compiled version is the same as the
       run-time; there is  a huge probability that the structures are different;
       it is better to not have the functionality then blow up the program!
    */
    if(xmUseVersion == XmVersion)
    {
	OutputData data = ((XmTextWidget)w)->text.output->data;

	data->tabwidth = tabsize * data->averagecharwidth;

	return True;
    }
    else
    {
	fprintf(stderr, "\nasedit Warning: cannot set tabsize! Run-time Motif library is ");
	fprintf(stderr, "\nincompatible with the one used during compilation!\n");
	return False;
    }

} /* setTabSize */



#ifdef _NO_PROTO
static void setUserTabSizes(win, newTabsize)
    aseditWindowStruct *win;
    int newTabsize;
#else  /* _NO_PROTO */

static void setUserTabSizes(aseditWindowStruct *win, int newTabsize)
#endif
{
    /* set the tab size for all main edit text widgets; do that only
       when the new tabsize is different from the previous one or
       when is different from the default tabsize (8);
       check for successful setting of the tab (private Motif data)
    */

    if(win->tabsize == newTabsize && newTabsize == 8 ) return;	/* nothing to do */

    /* check, and correct if necessary, the newTabsize */
    if(newTabsize < 1) newTabsize = 1;
    if(newTabsize > MAX_TABSIZE) newTabsize = MAX_TABSIZE;


    if(win->edit_text && setTabSize(win->edit_text, newTabsize))
		win->tabsize = newTabsize;

} /* setUserTabSizes */


#ifdef _NO_PROTO
static void postQuickMenu(w, client_data, event)
    Widget w;
    XtPointer client_data;
    XEvent *event;
#else  /* _NO_PROTO */

static void postQuickMenu(Widget w, XtPointer client_data, XEvent *event)
#endif
{
    XButtonPressedEvent *bevent = (XButtonPressedEvent *) event;
    aseditWindowStruct *win = (aseditWindowStruct *)client_data;

    if (bevent->button != 3)
        return;


    /* position the menu at the location of the button press */
    if(win->quick_access_popup)		/* sanity check */
    {
	if(win->can_undo) XtSetSensitive(win->popup_undo_button,   True);
	else	          XtSetSensitive(win->popup_undo_button,   False);

	/* set the sensitivity for the Cut/Paste buttons */

	if(textSelected(win))
	{
	    if(!win->file_read_only)
	    {
		XtSetSensitive(win->popup_cut_button,   True);
	    }
	    else
	    {
		XtSetSensitive(win->popup_cut_button,   False);
	    }
	    XtSetSensitive(win->popup_copy_button,  True);
	}
	else
	{
	    XtSetSensitive(win->popup_cut_button,   False);
	    XtSetSensitive(win->popup_copy_button,  False);
	}
	/* check also if some other application did not filled up Clipboard (and that
	   was empty before that call)
	 */
	if(!clipboard_filled)
	{
	    Atom      clipboard_atom = XmInternAtom(display, "CLIPBOARD", False);
	    if(XGetSelectionOwner(display, clipboard_atom))
	    {
		set_paste_buttons();  /* set sensitivity of all paste buttons */
		clipboard_filled = True;
	    }
	}


	XmMenuPosition (win->quick_access_popup, bevent);
	XtManageChild (win->quick_access_popup);
    }


}   /* postQuickMenu */

#ifdef _NO_PROTO
void CreatePopupMenus(win, parent)
    aseditWindowStruct *win;
    Widget 		parent;
#else  /* _NO_PROTO */
void CreatePopupMenus(aseditWindowStruct *win, Widget parent)
#endif
{
    int ac;

    as_create_popup_menu(NULL, parent, Popup_list,
                         XtNumber(Popup_list), charset);

    /* Add the event handler (postQuickMenu()) and pass the win structure 
     * as the client_data.  
     * Add the event handler for the 3rd mouse button (Motif compliance)
     */
    XtAddEventHandler (parent, ButtonPressMask, False, (XtEventHandler)postQuickMenu, (XtPointer)win);

    /* setting the specific widgets (they must be accessible from other
      procedures) to widgets created in the as_create_poup_menu procedure */
    /*****  watch out to set these properly !!!!! (it's an ugly hack ...) */

    win->quick_access_popup = Popup_list[0].w;

    ac = 0;
    win->popup_undo_button  = Qaccess_popup[ac++].w;
    ac++;						/* separator in the menu */
    win->popup_cut_button   = Qaccess_popup[ac++].w;
    win->popup_copy_button  = Qaccess_popup[ac++].w;
    win->popup_paste_button = Qaccess_popup[ac++].w;
#ifdef USE_FIND_NEXT_IN_QACCESS
    ac++;						/* separator */
    ac++;						/* don't need repeat button (find next) */
#endif
    ac++;						/* separator */
    ac++;						/* don't need open button*/
    win->popup_save_button  = Qaccess_popup[ac++].w;
    ac++;						/* separator */
							/* don't need exit button */

    /* set up initial sensitivity of the buttons */
    XtSetSensitive(win->popup_undo_button,   False);
    XtSetSensitive(win->popup_cut_button,    False);
    XtSetSensitive(win->popup_copy_button,   False);
    XtSetSensitive(win->popup_paste_button,  False);
    XtSetSensitive(win->popup_save_button,   False);


}  /* CreatePopupMenus */

#ifdef _NO_PROTO
void make_window(win)
    aseditWindowStruct *win;
#else  /* _NO_PROTO */
void make_window(aseditWindowStruct *win)
#endif
{
    Widget          main;           /*  MainWindow          */
    Widget          menu_bar;       /*  RowColumn           */
    Widget          work_area;      /*  work area in the main widget */

    Arg             al[10];         /*  arg list            */
    register int    ac;             /*  arg count           */
    char            *work;          /* work string */
    Atom            wm_delete_window;       /* used with for WM_DELETE_WINDOW */
    Atom            wm_quit_appl;           /* used with _WM_QUIT_APPL on SGI */
    Atom            clipboard_atom;         /* to check if we have something in the clipboard */

    /*      Create MainWindow.      */
    ac = 0;
    XtSetArg (al[ac], XmNshadowThickness, 0);  ac++;
    main = XmCreateMainWindow (win->topshell, "main", al, ac);
    XtManageChild (main);


    /*      Create and manage all menus     */
    menu_bar = CreateMenus (win, main);



   /* setting extra callbacks for sensitivity of edit& tools menu buttons */
   {
	Widget pane;
	/* the the pane widget (row column) from subMenuId of
	    the cascading button
	*/
	ac = 0;
	XtSetArg (al[ac], XmNsubMenuId, &pane);  ac++;
	XtGetValues(Main_menu[1].w, al, ac);

	/* now register map callback to be called before pane is mapped
	   and unmap callback called after pane is unmapped
	*/
	XtAddCallback(pane, XmNmapCallback,
		   (XtCallbackProc)MapEditCB, mk_asdat_w(win, MENU_EDIT) );
	XtAddCallback(pane, XmNunmapCallback,
		   (XtCallbackProc)MapEditCB, mk_asdat_w(win, MENU_EDIT) );

	/* now tools menu */
	ac = 0;
	XtSetArg (al[ac], XmNsubMenuId, &pane);  ac++;
	XtGetValues(Main_menu[TOOLS_MENU_POS].w, al, ac);

	XtAddCallback(pane, XmNmapCallback,
		   (XtCallbackProc)MapToolsCB, mk_asdat_w(win, MENU_TOOLS) );
	XtAddCallback(pane, XmNunmapCallback,
		   (XtCallbackProc)MapToolsCB, mk_asdat_w(win, MENU_TOOLS) );

   }

    /* create popup menu(s) under the main */
    CreatePopupMenus(win, main);




    win->menu_bar = menu_bar;

    /* 	Creation of each dialog in asedit 1.2x is postponed until
	it is needed (they are with one exception children of menu_bar)
    */
    if(win->prev == NULL) install_as_images(toplevel /***menu_bar***/);   /* install it only for the first time
				note that the parent *must* be toplevel because other parents
				might be destroyed  */

    /* create work area in main widget */
    work_area = CreateEditWorkArea(win, main);

    setUserTabSizes(win, lstr.tabSize);	/* set user defined tab size */



    /* check if the user did not requested that at the startup the status line 
       should be switched off
    */
    if(!lstr.defaultStatus)
    {
       XtUnmanageChild(win->frame_bottom);
       win->status_line_on = False;
    }

    /*      Set areas of MainWindow         */
    XmMainWindowSetAreas (main, menu_bar, NULL, NULL, NULL,
					work_area);



    set_asedit_icon(win->topshell, win->edit_text, PROGRAM_NAME);


    /*      Realize topshell widget.       */
    XtRealizeWidget (win->topshell);


#if (XtSpecificationRelease > 3)
    wm_delete_window = XmInternAtom(display, "WM_DELETE_WINDOW", False);
    wm_quit_appl = XmInternAtom(display, "_WM_QUIT_APP", False);
    XmAddWMProtocolCallback(win->topshell, wm_delete_window,
			(XtCallbackProc) ControlCloseCB, mk_asdat(0) );
    XmAddWMProtocolCallback(win->topshell, wm_quit_appl,
			(XtCallbackProc) ControlCloseCB, mk_asdat(0) );


    ac = 0;
    XtSetArg (al[ac], XmNdeleteResponse,XmDO_NOTHING);  ac++;
    XtSetValues(win->topshell, al, ac);

#endif

    aseditWinCount++;		/* increase the count of active windows */

    /*  Pop the window (topshell) up. */
    XtPopup (win->topshell, XtGrabNone);
    XFlush (display);
    XSync (display, False);



}   /*  make_window */


#ifdef _NO_PROTO
void next_window(win_prev)
    aseditWindowStruct *win_prev;
#else  /* _NO_PROTO */
void next_window(aseditWindowStruct *win_prev)
#endif
{
    Arg             al[10];         /*  arg list            */
    register int    ac;             /*  arg count           */
    aseditWindowStruct *win=NULL;


    /* first create a new  aseditWindowStruct  structure */

    win = new_asedit_win(win_prev);

    /* store win as the last in the chain ... */
    asedit_last_window = win;

    ac = 0;
    if(win_prev != NULL)
    {
	/* not a first window, open it down and right ...*/
	Dimension x_prev, y_prev, scrx, scry, x, y, width, height;
	char geom[20];

	scrx = WidthOfScreen (XtScreen (toplevel));
	scry = HeightOfScreen (XtScreen (toplevel));

	ac = 0;
	XtSetArg(al[ac], XmNx,      &x_prev);	ac++;
	XtSetArg(al[ac], XmNy,      &y_prev);	ac++;
	XtSetArg(al[ac], XmNwidth,  &width);	ac++;
	XtSetArg(al[ac], XmNheight, &height);	ac++;
	XtGetValues (win_prev->topshell, al, ac);

	/* Try open down and right 50 pixels...(if not possible correct it) */
	x = x_prev + 50;
	y = y_prev + 50;
	/* If not possible, deal with it... */
	while ((Dimension)(x + width)  > scrx)    x -= 100;
	while ((Dimension)(y + height) > scry)    y -= 100;

	sprintf (geom, "+%d+%d\0", x, y);

	ac = 0;
	XtSetArg (al[ac], XmNgeometry, (long)geom); ac++;
	XtSetArg (al[ac], XmNdefaultPosition, False); ac++;
	XtSetArg (al[ac], XmNwidth, width); 	ac++;
	XtSetArg (al[ac], XmNheight, height);	ac++;
    }
    else
    {	/* first window, check if it is needed to be iconic etc. */
	if (lstr.first_window_iconic)
		{ XtSetArg (al[ac], XmNiconic, True); ac++; }
	if (lstr.initial_geometry != NULL && strlen(lstr.initial_geometry))
		{ XtSetArg (al[ac], XmNgeometry, (long)lstr.initial_geometry); ac++; }
    }
    XtSetArg(al[ac], XmNtitle, PROGRAM_NAME); ac++;

    win->topshell = XtCreatePopupShell ("asedit", topLevelShellWidgetClass,
			     toplevel, al, ac);

#if (XtSpecificationRelease > 4)
    /* X11R5 editres addition ...... */
#ifndef _NO_XMU
    XtAddEventHandler(win->topshell, (EventMask)0, True, _XEditResCheckMessages, NULL);
#endif
#endif

    make_window(win);

}   /* next_window */





#ifdef _NO_PROTO
static void exitAction(win)
    aseditWindowStruct *win;
#else  /* ! _NO_PROTO */

static void exitAction(aseditWindowStruct *win)
#endif
{

    /* exit if there is no files open */
    if (win->changes_counter != 0L) /* display the 'save' message dialog */
    {
	/* be sure that the main window is not iconized (needed when called from interrupt) */
	XMapRaised (XtDisplay (win->topshell), XtWindow (win->topshell));

	win->reason_save_question = MENU_EXIT;
	show_save_changes_dialog(win);
    }
    else
    {
	CloseFile(win);	/* close up the file */
	removeWinAndExit(win);
    }
}   /* exitAction */

#ifdef _NO_PROTO
static void removeWinAndExit (win)
    aseditWindowStruct *win;
#else  /* ! _NO_PROTO */

static void removeWinAndExit (aseditWindowStruct *win)
#endif
{
    remove_asedit_win (win);
    if(!asedit_last_window) exit (0);	/* exit this program */
    else
    {
	/* before 1.3 we exit only single window;
	   in 1.3 we make a recursive call to exit all windows!!
	*/
	asedit_last_window->reason_save_question = MENU_EXIT;  /* set the reason ! */
	exitAction(asedit_last_window);	/* !!! recursive call in 1.3 */

    }
}   /* removeWinAndExit */

/*****************************  MenuCB  *************************************
**
**	Process callbacks from PushButtons in PulldownMenus.
*/
#ifdef _NO_PROTO
void MenuCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void MenuCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
/*    Comment for novice users:
**    in Motif standard callback parameters are as follows:
**    Widget		w;		-   widget id
**    XtPointer		client_data;	-   data from application
**    XtPointer		call_data;	-   data from widget class
*/
{

    register int ac;		/* arg count		    */
    Arg al[10];			/* arg list		    */
    char *command;		/* command used in printing */
    char      work[326];	/* work string: max. file name ~256 + strings ... */

    int id 		    = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);
    Boolean  res;


    TurnWatchCursor(True);
    switch (id)
    {
	case MENU_OPEN:
	    /* version 1.2x - we open a new window so simply put the open dialog */
	    show_open_dialog(win);
	    break;

	case MENU_NEW:
	    /* If all files have been closed run the new file in the current window
	       i.e. do NOT create a new window (change implemented in 1.3.2) */
	    if(aseditWinCount == 1 && win->filename == NULL && 
			win == asedit_last_window) 	/* the last is a sanity check */
	    {
	    	open_file_in_last_window(NULL);   /* open a new default file ...  */
	    }
	    else
	    {	/* pre 1.3.2 version follows */
	    	next_window(asedit_last_window);
	    	open_file_in_last_window(NULL);   /* open a new default file ...  */
	    }
	    break;

	case MENU_CLOSE:
	    if (win->changes_counter != 0L) /* display the 'save' message dialog */
	    {
		win->reason_save_question = id;
		show_save_changes_dialog(win);
	    }
	    else
	    {
		CloseFile(win);
		if(aseditWinCount > 1)	remove_asedit_win (win); /* ver. 1.3 close
								causes closing window
								as well (if not the last one) */
	    }
	    break;

	case MENU_SAVE:
	    /* first check if the name is not a default NoName ... if so
	       call save_as with empty name */
	    win->reason_save_question = id;
	    if(strncmp(win->filename, lstr.noname, strlen(lstr.noname)) == 0)
	    {
		show_save_as_dialog(win, NULL);
	    }
	    else
	    {
		/* create a backup file and write the current text to a file */
		if(!SaveFile(win))
		{	/* generate error message that file can't be saved */


		    /* new 1.3 version follows */
			sprintf(work, (char *)lstr.fm_unable_to_save, win->filename);

		    show_error_message(win, work);
		}
	    }
	    break;

	case MENU_SAVE_AS:
	    /* Display the 'save as' dialog with the present filename displayed in it. */
	    win->reason_save_question = id;
	    if(strncmp(win->filename, lstr.noname, strlen(lstr.noname)) == 0)
			show_save_as_dialog(win, NULL);
	    else
	    {
		/* let's get the event time needed for the selection(send that using
			 win->timestamp_search_request)  */
		XmAnyCallbackStruct * cb = (XmAnyCallbackStruct *) call_data;
		win->timestamp_search_request = cb->event->xbutton.time;
		show_save_as_dialog(win, win->filename);
	    }
	    break;

	case MENU_INSERT:
	    show_insert_dialog(win);
	    break;

	case MENU_PRINT:

	    show_print_dialog(win);
	    break;

	case MENU_EXIT:
	    exitAction(win);
	    break;


	case MENU_UNDO:
	case MENU_REDO:
	    UndoRedo(win, id);
	    break;


#if (XmVersion == 1000)
	/* for Motif 1.0.x  functions dealing with clipboard do not exist
	       - use my old functions */
	case MENU_CUT:
	case MENU_COPY:	/* action is the same, except that for MENU_CUT
				   the primary selection is deleted also */
	    {
		/* needed to get the event time */
		XmAnyCallbackStruct * cb = (XmAnyCallbackStruct *) call_data;
		char *selected_string = XmTextGetSelection (win->edit_text); /* text selection    */

		/* call a routine to copy a selection to the clipboard */
		/* allow pasting when an item is sucessfully copied to the clipboard */
		if( CopyStringToClipboard(selected_string,cb->event->xbutton.time) )
		{
		    if(!clipboard_filled) set_paste_buttons();	/* set sensitivity ... */
		    clipboard_filled = True;
		}
		if(selected_string != NULL)
			XtFree(selected_string);   /* free allocated memory */
		/* call routine to delete primary selection (only for the cut option)*/
		if( id == MENU_CUT)	DeletePrimarySelection(win->edit_text);
	    }
	    break;

	case MENU_PASTE:
	    /* call the routine that paste the text at the cursor position */
	    PasteItemFromClipboard(win->edit_text);
	    break;

	case MENU_CLEAR:
	    /* call routine to delete primary selection */
	    DeletePrimarySelection(win->edit_text);
	    break;
#else
	/* since Motif 1.1 text clipboard functions are defined as standard - use them */

	case MENU_CUT:
	    /* two version are integrated; SUN & non-SUN; see the comments for MENU_COPY */


	    	if(  (res = XmTextCut(win->edit_text, CurrentTime)) )
		{   /* cut successful */
		    if(!clipboard_filled) set_paste_buttons();        /* set sensitivity ... */
		    clipboard_filled = True;
		}


	    break;

	case MENU_COPY:

		if( (res = XmTextCopy(win->edit_text, CurrentTime)) )
		{   /* copy successful */
		    if(!clipboard_filled) set_paste_buttons();        /* set sensitivity ... */
		    clipboard_filled = True;
		}


	    break;

	case MENU_PASTE:

	    	res = XmTextPaste(win->edit_text);
	    break;

	case MENU_CLEAR:
	    /***XmTextClearSelection(win->edit_text, CurrentTime); ***OLD ***/
	    XmTextRemove(win->edit_text);
	    break;
#endif /* XmVersion == 1000 */

	case MENU_FIND:
	case MENU_CHANGE:
	    /* set the reason for managing replace_dialog  (it is important
	       because this dialog is shared between find & replace option, so only
	       one callback for each button was registered) */
	    win->search_reason = id;
	    show_replace_dialog(win);

	    break;

	case MENU_FIND_NEXT:
	    {
		XmAnyCallbackStruct * cb = (XmAnyCallbackStruct *) call_data;

		/* lets get the event time needed for the selection of the found string */
		win->timestamp_search_request = cb->event->xbutton.time;
	    }
	    win->nextSelectionSearch = True;	/* set it to distinguish this kind of search */
	    repeatOrSelectionFind(win);
	    break;

	case MENU_GOTOLINE:
	    show_gotoline_dialog(win);
	    break;

	case MENU_MARK_SET0:
	case MENU_MARK_SET1:
	case MENU_MARK_SET2:
	case MENU_MARK_SET3:
	case MENU_MARK_SET4:
	case MENU_MARK_SET5:
	case MENU_MARK_SET6:
	case MENU_MARK_SET7:
	case MENU_MARK_SET8:
	case MENU_MARK_SET9:
	    {
		int mark= id - MENU_MARK_SET0;
		XmTextPosition pos;
		/* get the value of the cursor position */
		XtSetArg(al[0], XmNcursorPosition, &pos);
                XtGetValues(win->edit_text, al, 1);
		win->mark_pos[mark] = pos;
		win->mark_set[mark] = True;
		win->marks_used     = True;
		XtSetSensitive( win->menu_mark_go_button[mark], True);
	    }
	    break;

	case MENU_MARK_GO0:
	case MENU_MARK_GO1:
	case MENU_MARK_GO2:
	case MENU_MARK_GO3:
	case MENU_MARK_GO4:
	case MENU_MARK_GO5:
	case MENU_MARK_GO6:
	case MENU_MARK_GO7:
	case MENU_MARK_GO8:
	case MENU_MARK_GO9:
	    {
		int mark = id -  MENU_MARK_GO0;
		XmTextSetCursorPosition(win->edit_text, win->mark_pos[mark]);  /* causes call to
					TextCB, so we don't have to worry about line, column numbers*/
	    }
	    break;

	case MENU_MATCH_FORWARD:
	case MENU_MATCH_BACKWARD:
	    {
		XmAnyCallbackStruct * cb = (XmAnyCallbackStruct *) call_data;

		/* lets get the event time needed for the selection of the delimited text */
		win->timestamp_search_request = cb->event->xbutton.time;
	    }
	    if(id == MENU_MATCH_FORWARD) findDelimiterMate(win, True);
	    else 			 findDelimiterMate(win, False);
	    break;

	case MENU_H_ABOUT:
	    show_about_message(win);
	    break;


	case MENU_SPELL:
	    executeFilterCmd(win, (char *)lstr.spellCmd, lstr.spellExt, True);
	    break;

	case MENU_SORT:
	    executeFilterCmd(win, (char *)lstr.sortCmd, lstr.sortExt, True);
	    break;

	case MENU_FORMAT_MOVE_LEFT:
	    show_moveLeft_dialog(win);
	    break;

	case MENU_FORMAT_MOVE_RIGHT:
	    show_moveRight_dialog(win);
	    break;

	case MENU_FORMAT_INDENT_WITH:
	    show_indentWith_dialog(win);
	    break;

	case MENU_FORMAT_REFORMAT:
	    show_reformat_dialog(win);
	    break;

	case MENU_EXPAND:
	    /* we assume that the expand definition include a "%d" specifier for
	       writing out the tabstop value
	    */
	    sprintf(work, lstr.expandCmd, win->tabsize);
	    executeFilterCmd(win, work, lstr.expandExt, True);
	    break;

	case MENU_UNEXPAND:
	    sprintf(work,  lstr.unexpandCmd, win->tabsize);
	    executeFilterCmd(win, work, lstr.unexpandExt, True);
	    break;

	case MENU_FILTER_EXTRA:
	    show_filter_dialog(win);
	    break;

	case MENU_FILTER_0:
	    executeFilterCmd(win, (char *)lstr.filter0, lstr.filterExt0, True);
	    break;
	    	
	case MENU_FILTER_1:
	    executeFilterCmd(win, (char *)lstr.filter1, lstr.filterExt1, True);
	    break;

	case MENU_FILTER_2:
	    executeFilterCmd(win, (char *)lstr.filter2, lstr.filterExt2, True);
	    break;
	    	
	case MENU_FILTER_3:
	    executeFilterCmd(win, (char *)lstr.filter3, lstr.filterExt3, True);
	    break;
	    	
	case MENU_FILTER_4:
	    executeFilterCmd(win, (char *)lstr.filter4, lstr.filterExt4, True);
	    break;
	    	
	case MENU_FILTER_5:
	    executeFilterCmd(win, (char *)lstr.filter5, lstr.filterExt5, True);
	    break;
	    	
	case MENU_FILTER_6:
	    executeFilterCmd(win, (char *)lstr.filter6, lstr.filterExt6, True);
	    break;
	    	
	case MENU_FILTER_7:
	    executeFilterCmd(win, (char *)lstr.filter7, lstr.filterExt7, True);
	    break;
	    	
	case MENU_FILTER_8:
	    executeFilterCmd(win, (char *)lstr.filter8, lstr.filterExt8, True);
	    break;

	case MENU_FILTER_9:
	    executeFilterCmd(win, (char *)lstr.filter9, lstr.filterExt9, True);
	    break;

	case MENU_CASE_UPPER:
	    changeCaseOfSelection(win, TO_UPPER_CASE);
	    break;

	case MENU_CASE_LOWER:
	    changeCaseOfSelection(win, TO_LOWER_CASE);
	    break;

	case MENU_CASE_TITLE:
	    changeCaseOfSelection(win, TO_TITLE_CASE);
	    break;

	case MENU_CASE_TOGGLE:
	    changeCaseOfSelection(win, TO_TOGGLE_CASE);
	    break;


	case MENU_COMMAND_EXTRA:
	    show_command_dialog(win);
	    break;

	case MENU_COMMAND_0:
	    executeFilterCmd(win, lstr.cmdDef0, lstr.cmdExt0, False);
	    break;

	case MENU_COMMAND_1:
	    executeFilterCmd(win, (char *)lstr.cmdDef1, lstr.cmdExt1, False);
	    break;

	case MENU_COMMAND_2:
	    executeFilterCmd(win, (char *)lstr.cmdDef2, lstr.cmdExt2, False);
	    break;

	case MENU_COMMAND_3:
	    executeFilterCmd(win, (char *)lstr.cmdDef3, lstr.cmdExt3, False);
	    break;

	case MENU_COMMAND_4:
	    executeFilterCmd(win, (char *)lstr.cmdDef4, lstr.cmdExt4, False);
	    break;

	case MENU_COMMAND_5:
	    executeFilterCmd(win, (char *)lstr.cmdDef5, lstr.cmdExt5, False);
	    break;

	case MENU_COMMAND_6:
	    executeFilterCmd(win, (char *)lstr.cmdDef6, lstr.cmdExt6, False);
	    break;

	case MENU_COMMAND_7:
	    executeFilterCmd(win, (char *)lstr.cmdDef7, lstr.cmdExt7, False);
	    break;

	case MENU_COMMAND_8:
	    executeFilterCmd(win, (char *)lstr.cmdDef8, lstr.cmdExt8, False);
	    break;

	case MENU_COMMAND_9:
	    executeFilterCmd(win, (char *)lstr.cmdDef9, lstr.cmdExt9, False);
	    break;





	default:
	    /* an unknown client_data was received and there is no setup to handle this */
	    fprintf(stderr, "Warning: an unknown client_data in menu callback\n");
	    break;
    }
    TurnWatchCursor(False);

} /* MenuCB */


#ifdef _NO_PROTO
static void SaveFileAndCheckReason(win, w)
    aseditWindowStruct *win;
    Widget w;
#else  /* ! _NO_PROTO */

static void SaveFileAndCheckReason(aseditWindowStruct *win, Widget w)
#endif
{
    char 	    work[326];	    /* work string: max. file name ~256 + strings ... */

    /* to be called from inside Dialog callbacks (NOT menu callback) because
       we explicitly unmanage widget w (i.e. the dialog !
    */
    /* save the current file, unmanage the dialog and simply proceed
       with the action that prompted the action */
    if(!SaveFile(win))
    {	

        if(win->changes_counter)
        {
            /* for unsuccesful overwrite restore the changeHint !!! */
	    set_titles_mwindow_icon(win, win->filename, (char *)lstr.changeHint);
	}


	/* generate error message that file can't be saved */
	

	    sprintf(work, (char *)lstr.fm_unable_to_save, win->filename);

	if( win->reason_save_question == MENU_CLOSE)
		strcat(work,	(char *)lstr.fm_not_closed);
	if( win->reason_save_question == MENU_EXIT)
		strcat(work,	(char *)lstr.fm_exit_aborted);
	XtUnmanageChild (w);
	show_error_message(win, work);
	if( win->reason_save_question == MENU_EXIT ||
	    win->reason_save_question == MENU_CLOSE)
			return;		/* do not proceed the original action */
    }
    else XtUnmanageChild (w);		/* popdown the save question */

    switch(win->reason_save_question)
    {
	case MENU_CLOSE:
	    CloseFile(win);
	    if(aseditWinCount > 1)	remove_asedit_win (win); /* ver. 1.3 close
								causes closing window
								as well (if not the last one) */
	    break;
	case MENU_EXIT:
	    removeWinAndExit(win);
	    break;

	case MENU_SAVE:
	case MENU_SAVE_AS:
		;	/* Do nothing */
		break;

	default:
	    /* an unknown reason_save_question */
	    fprintf (stderr, "Warning: an unknown reason_save_question in accept callback \n");
	    break;
    }
    return;

}   /* SaveFileAndCheckReason */




#ifdef _NO_PROTO
void find_or_change_action(win, call_data, start)
    aseditWindowStruct *win;
    XtPointer call_data;
    Boolean start;
#else  /* ! _NO_PROTO */

void find_or_change_action(aseditWindowStruct *win, XtPointer call_data, Boolean start)
#endif
{

    /* there may be two reasons for this callback:
       one comes from find option and the second from change
       option; therefore we treat them separately */

    if(win->search_string) { XtFree(win->search_string); win->search_string=NULL; }
    /* get the search string */
    win->search_string = (char *)XmTextGetString(win->text_to_find);
    {   /* grouping brackets to use local *scb */
	XmSelectionBoxCallbackStruct *scb =
		(XmSelectionBoxCallbackStruct *) call_data;

	/* set the timestamp needed to set selection (it is
	   needed for the Search option as well ) */
	win->timestamp_search_request = scb->event->xkey.time;
    }

    /* let's set the search again button to sensitive no matter (!)
       if the search or change actions happened */
    if(win->search_string != NULL && (strlen(win->search_string) > (size_t)0))
	XtSetSensitive(win->menu_find_again_button,   True);

    if(win->search_reason == MENU_FIND)   /* find operation */
    {
	find_string(win, start);
    }
    else
    {   /* find & confirm change operation */
	if(win->new_string)  { XtFree(win->new_string);  win->new_string=NULL; }
	win->new_string = (char *)XmTextGetString(win->new_text);
	find_string(win, start);
	/* if the string was found prompt up the change prompt */
	if(win->found_string_start_pos >= 0L ) show_change_prompt(win);
    }

}   /* find_or_change_action */

#ifdef _NO_PROTO
void prepare_change_all(win, call_data)
    aseditWindowStruct *win;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void prepare_change_all(aseditWindowStruct *win, XtPointer call_data)
#endif

{
    XmSelectionBoxCallbackStruct *scb =
	(XmSelectionBoxCallbackStruct *) call_data;

    /* get the strings ... */
    if(win->search_string) { XtFree(win->search_string); win->search_string=NULL; }

    /* get the search string */
    win->search_string = (char *)XmTextGetString(win->text_to_find);

    if(win->new_string)  { XtFree(win->new_string);  win->new_string=NULL; }
    win->new_string = (char *)XmTextGetString(win->new_text);

    /* set the timestamp needed to set selection (it is
       needed for the Search option as well ) */
    win->timestamp_search_request = scb->event->xkey.time;

    /* let's set the search again button to sensitive */
    if(win->search_string != NULL  && (strlen(win->search_string) > (size_t)0))
    {
	XtSetSensitive(win->menu_find_again_button,   True);

	/* we make insensitive the "Find & Verify" and "Change All" buttons
	   to show the user which dialog he should concentrate on
	   and not to confuse him */
	/* do that only when we have something to search for;
	   (correction of the bug reported by Roger)
	 */

	set_change_buttons_sensitivity(win, False);
    }

}   /* prepare_change_all */

#define MAX_MOVE_RIGHT_VALUE 		99

/*****************************  DialogOkCB  *********************************
**
**	Process callback from Dialog OK actions.
*/
#ifdef _NO_PROTO
void DialogOkCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void DialogOkCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
{
    FILE *fout;		/* used to test if the specified file exists */
    static char *save_as_filename=NULL;  /* new file name; temporary pointer -
			- the allocated memory should not be freed if
			this pointer is assigned later on to the filename */
    char 	    work[326];	    /* work string: max. file name ~256 + strings ... */
    Arg		    al[5];
    register int    ac;

    int id 		    = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);


    TurnWatchCursor(True);
    switch ( id )
    {
	case DIALOG_OPEN:
	    {
		XmFileSelectionBoxCallbackStruct *fcb =
                         (XmFileSelectionBoxCallbackStruct *) call_data;
                char *filename=NULL;
		XmStringGetLtoR(fcb->value, charset, &filename);
		/* first check if the file name is meaningless (an empty string
                   or string consisting only from spaces)
		   if it is  pop-up an appropriate message and do not
                   popd-down the dialog box
                */
                if(empty_name(filename))
                {
                    /* popup the error message about empty file name */
                    sprintf(work, "%s", (char *)lstr.fm_no_filename);
		    show_error_message(win, work);
		    if(filename != NULL) XtFree(filename);
		    break;
                }
		else XtFree(filename);	/* if we combine the above with what is below
					   do NOT free filename until it is not 
					   needed any more */
	    }
		
	    /* Correction for 1.3.2 veersion:
	       If the current window is Noname and nothing has been changed
	       open the file in this window (instead of creating a new one)
	    */
	    if(win->filename != NULL && 
		strncmp(win->filename, lstr.noname, strlen(lstr.noname)) == 0)
	    {
		if(win->changes_counter == 0L )
	        {
		    XtFree(win->filename); win->filename = NULL;
		}
	    }

	    /* if there is a file in the current window open a new window;
		otherwise just open the file and read it into the text widget
		in the current window
	    */
	    if (win->filename != NULL)
	    {
		/* create a new window and load the file selected */
		XmFileSelectionBoxCallbackStruct *fcb =
			 (XmFileSelectionBoxCallbackStruct *) call_data;
		char *filename=NULL;

		next_window(asedit_last_window);
		XtUnmanageChild (w);	/* popdown the file selection box */

		/* get the filename from the file selection box */
		XmStringGetLtoR(fcb->value, charset, &filename);

		/* set the file_read_only to the value requested by the user */
		if(win->view_only_toggle!= NULL)         /* safety check */
		   asedit_last_window->file_read_only = XmToggleButtonGetState(win->view_only_toggle);


		open_file_in_last_window(filename);
		if(filename != NULL) XtFree(filename);
	    }
	    else
	    {
		 XmFileSelectionBoxCallbackStruct *fcb =
			 (XmFileSelectionBoxCallbackStruct *) call_data;

		/* get the filename from the file selection box */
		XmStringGetLtoR(fcb->value, charset, &(win->filename));

		/* set the file_read_only to the value requested by the user */
		if(win->view_only_toggle!= NULL)         /* safety check */
		   win->file_read_only = XmToggleButtonGetState(win->view_only_toggle);


		/* open file if it exists, if not set the empty text;
		   if file can't be opened or created show error message and
		   close the previous file */

		if (!OpenFile(win, False))    /* OpenFile is called with only_existing_files = False */
		{
		    sprintf(work, (char *)lstr.fm_unable_to_open, win->filename);
		    /* popdown the selection box - it is important
		       to do that before popup of the error_message  because
		       otherwise the current window lose focus !! */
		    XtUnmanageChild (w);
		    show_error_message(win, work);
		    if(win->filename != NULL) {XtFree(win->filename); win->filename = NULL; }
		}
		else XtUnmanageChild (w);    /* popdown the file selection box */
	    }
	    break;

	case DIALOG_SAVE_CHANGES:
	    /* first check if the name is not a default NoName ... if so
	       call save_as with empty name */
	    if(strncmp(win->filename, lstr.noname, strlen(lstr.noname)) == 0)
	    {
		XtUnmanageChild(w);
		show_save_as_dialog(win, NULL);
	    }
	    else SaveFileAndCheckReason(win, w);
	    break;


	case DIALOG_SAVE_AS:
	    { /* grouping brackets to use local *scb */
		XmFileSelectionBoxCallbackStruct *scb =
			 (XmFileSelectionBoxCallbackStruct *) call_data;
		/* free the memory .. (it happens when save as was selected,
		   a file with such a name existed already and the user
		   answered Cancel to overwrite question )  */
		if (save_as_filename != NULL)
			{ XtFree(save_as_filename); save_as_filename = NULL; }
		/* get the new filename string from the file selection box */
		XmStringGetLtoR(scb->value, charset, &save_as_filename);
	    }

	    /* first check if the file name is meaningful (not an empty string
		or string consisting only from spaces)
		if it is an empty string pop-up an appropriate message and do not
		popd-down the dialog box
	    */
	    if(empty_name(save_as_filename))
	    {
		/* popup the error message about empty file name */
		sprintf(work, "%s", (char *)lstr.fm_no_filename);
		show_error_message(win, work);
		break;
	    }

	    /* check if the file is regular; if not show error message */
	    if(!isFileRegular(save_as_filename))
	    {
		sprintf(work, (char *)lstr.fm_not_regular, save_as_filename);
		show_error_message(win, work);
		break;
	    }

	    /* check  if such a file already exists; if it exists
	       ask if it should be overwritten or not; if such a file
	       does not exist just save the file with the new name */

	    if ((fout = fopen(save_as_filename, "r")) != NULL)
	    {	/* file already exist ... - popup appropriate dialog */
		fclose(fout);
		XtUnmanageChild (w);
		show_overwrite_question(win, save_as_filename);
	    }
	    else
	    {   /* save as .... */
		/* free the old file name memory */
		if (win->filename != NULL) { XtFree(win->filename); win->filename = NULL; }
		win->filename = save_as_filename;	/* use this name */
			save_as_filename = NULL;
		/* setting a new title of the main window and the icon name.
		   They include the new name of the file */
		set_titles_mwindow_icon(win, win->filename, NULL);


		SaveFileAndCheckReason(win, w);
	    }
	    break;

	case DIALOG_INSERT:
	    {
		char * file_string=NULL;     /* Contents of file.      */
		char * filename = NULL;
		Boolean         read_only;           /* shows the file read only status */
		XmFileSelectionBoxCallbackStruct *fcb =
                         (XmFileSelectionBoxCallbackStruct *) call_data;

                /* get the filename from the file selection box */
                XmStringGetLtoR(fcb->value, charset, &filename);

		/* first check if the file name is meaningless (an empty string
		   or string consisting only from spaces)
		   if it is  pop-up an appropriate message and do not
		   popd-down the dialog box
		*/
		if(empty_name(filename))
		{
		    /* popup the error message about empty file name */
		    sprintf(work, "%s", (char *)lstr.fm_no_filename);
		    show_error_message(win, work);
		    if(filename != NULL) XtFree(filename);
		    break;
		}

		if( (file_string = ReadFile(filename, &read_only)) != (char *)NULL)
		{
		    XmTextPosition cursorPos;	/* insert in the current position */
		    XtSetArg(al[0], XmNcursorPosition, &cursorPos);
		    XtGetValues(win->edit_text, al, 1);

		    /* insert new text */
		    XmTextReplace(win->edit_text, cursorPos, cursorPos, file_string);

		    XtUnmanageChild(w);
		    XtFree(file_string);
		}
		else
		{
		    sprintf(work, (char *)lstr.fm_unable_to_open, filename);

		    /**XtUnmanageChild (w);  give him/her another chance (DO NOT unmanage).... */
		    show_error_message(win, work);
		}

	    }
	    break;


	case QUESTION_OVERWRITE:
	    /* overwrite the existing file ... */
	    /* free the old file name memory */
	    if (win->filename != NULL) { XtFree(win->filename); win->filename = NULL; }
	    win->filename = save_as_filename;	/* use this name */
	    save_as_filename = NULL;        /* set to NULL in order
					not to free memory allocated
					for save_as_filename (now it
					is used by filename !) */
	    /* setting a new title of the main window and the icon name.
	       They include the new name of the file */
	    set_titles_mwindow_icon(win, win->filename, NULL);


	    SaveFileAndCheckReason(win, w);
	    break;

	case DIALOG_PRINT_NEW:
	    {   /* grouping brackets to use local *scb */
		XmSelectionBoxCallbackStruct *scb =
			 (XmSelectionBoxCallbackStruct *) call_data;
		Boolean print_ok = True;
		char *print_cmd=NULL;
		char *text_string=NULL;		/* text to be printed */

		/* get the print commnad string from the selection box */
		XmStringGetLtoR(scb->value, charset, &print_cmd);
		if(!empty_name(print_cmd))
		{
		    if(win->print_complete_toggle!= NULL)	/* safety check */
		    {
			if(XmToggleButtonGetState(win->print_complete_toggle))
			{
			    /* get the text of the whole file */
			    text_string = (char *)XmTextGetString(win->edit_text);
			}
			else
			{
			    /* get the selection only */
			    text_string = XmTextGetSelection(win->edit_text);
			    if((text_string == NULL) || (strlen(text_string) == 0))
			    {
				/* popup the error message about non-existent selection */
				sprintf(work, "%s",  (char *)lstr.fm_no_selection);
				show_error_message(win, work);
				if(print_cmd)   XtFree(print_cmd);
				if(text_string) XtFree(text_string);
				break;
			    }
			}


			print_ok = PrintString(text_string, print_cmd);
			if(text_string) XtFree(text_string);   /* free allocated memory */
			if(print_cmd)   XtFree(print_cmd);

		    }
		    XtUnmanageChild(w);		/* pop-down the dialog */
		    if(!print_ok)  show_error_message(win, (char *)lstr.fm_print_failed);
		}
		else
		{
		    /* popup the error message about empty print command string */
		    sprintf(work, "%s", (char *)lstr.fm_no_printer);
		    show_error_message(win, work);
		    if(print_cmd != NULL) XtFree(print_cmd);
		}
	    }
	    break;


	case DIALOG_FIND_OR_CHANGE:
	    win->nextSelectionSearch = False;
	    find_or_change_action(win, call_data, True);	/* True because
						we start the action (it is not
						a continuation of the previous one
						during wchich we hit the EOF) */
	    break;

	case DIALOG_GOTOLINE:
	    {   /* grouping brackets to use local *scb */
		XmSelectionBoxCallbackStruct *scb =
			 (XmSelectionBoxCallbackStruct *) call_data;
		long line_no;
		char   *line_string=NULL;

		/* get the line number string from the gotoline prompt box */
		XmStringGetLtoR(scb->value, charset, &line_string);

		line_no = atol(line_string);	/* convert the string into the line number */
		/* free the memory allocated for line_string, because it is no longer needed */
		XtFree(line_string);

		go_to_line(win, line_no, False);
	    }
	    break;

	case DIALOG_CHANGE_PROMPT:
	    /* the first and last position of the string to change
	       has been set already so just use them ... */
	    XmTextReplace(win->edit_text, win->found_string_start_pos, win->found_string_end_pos, win->new_string);


	    /* now the find and verify should be continued .... */
	    find_string(win, True);
	    if(win->found_string_start_pos < 0L )
	    {
		XtUnmanageChild(w);
		/* restore the sensitivity of the buttons  */
		set_change_buttons_sensitivity(win, True);
	    }
	    break;
	    

	case QUESTION_CONTINUE_SEARCH:
	    XtUnmanageChild(w);
	    /* check if we are to continue simple find (search) or we
	       have to continue change all operation
	    */
	    if(win->cntSearch.on)
	    {
		if(win->nextSelectionSearch)
    		{
        	    /* do not get the search string again; use the previous value;
           	       (we can't really get the string from the text_to_find because
           	       it might not exist yet!)
        	    */
        	    find_string(win, False);	/* just find the string again */
    		}

		else
		    find_or_change_action(win, call_data, False);        /*  False because
						it is a continuation of the previous
						action */
	    }
	    else
	    {
		XFlush(display);	/*  because the search options may take a long while
					    and the cursor is timed out lets explicitly flush the display*/
		change_all_found_strings(win, False);	/* continue the previous change
							all process (do not start a new one) */
	    }
	    break;


	case DIALOG_MOVE_LEFT:
	case DIALOG_MOVE_RIGHT:
	case DIALOG_INDENT_WITH:
	    {
		/* some common code for selections */
		XmSelectionBoxCallbackStruct *scb =
			 (XmSelectionBoxCallbackStruct *) call_data;
		int 	move_by;
		char   *txtEntry;		/* text from the dialog */
		XmTextPosition left, right;	/* margins of the selection */
		char move_cmd[150];		/* the final part of the command */

		/* check the selection and get the selection positions */
		if(!XmTextGetSelectionPosition(win->edit_text, &left, &right) ||
			left == right)
		{
		    /* popup the error message about non-existent selection */
		    sprintf(work, "%s",  (char *)lstr.flt_no_selection);
		    show_error_message(win, work);
		    break;
		}

		/* get the value from the dialog; it must be something there and
		   for movement dialogs it must be non-zero
		*/
		XmStringGetLtoR(scb->value, charset, &txtEntry);
		if(txtEntry == NULL || (strlen(txtEntry) == 0) )
		{
		    /* popup the error message about non-existent parameter */
		    if(id == DIALOG_INDENT_WITH) sprintf(work, "%s",  (char *)lstr.flt_no_text);
		    else			 sprintf(work, "%s",  (char *)lstr.flt_no_value);
		    show_error_message(win, work);
		    if(txtEntry) XtFree(txtEntry);
		    break;
		}

		/* check for the zero value in movement action */
		if(id != DIALOG_INDENT_WITH)
		{
		    move_by = atoi(txtEntry);    /* convert the string into the value */
		    if(move_by == 0 || move_by > MAX_MOVE_RIGHT_VALUE)
		    {
			/* popup error message */
			sprintf(work, "%s",  (char *)lstr.flt_no_value);
			show_error_message(win, work);
			if(txtEntry) XtFree(txtEntry);
			txtEntry = NULL;
			break;
		    }
		}

		/* if we got here all is OK, proceed with action */

		/* start constructing the filter */
		sprintf(work, lstr.expandCmd, win->tabsize);

		if(id == DIALOG_MOVE_LEFT)
		    sprintf(move_cmd, " | sed 's/^ \\{1,%d\\}//' ",  move_by);	 /* delete max. move_by spaces */
		else if (id == DIALOG_MOVE_RIGHT)
		    sprintf(move_cmd, " | sed 's/^/%*s/' ",  move_by, " ");	 /* move_by spaces written */
		else
		    sprintf(move_cmd, " | sed 's/^/%s/' ",  txtEntry);	 /* indent with text */

		strcat(work, move_cmd);		/* put it together */
		executeFilterCmd(win, work, lstr.allFormatExt, True);	/* use the common Ext (probably NULL) */
		if(txtEntry) XtFree(txtEntry);

	    }
	    break;

	case DIALOG_REFORMAT:
	    {
		XmSelectionBoxCallbackStruct *scb =
			 (XmSelectionBoxCallbackStruct *) call_data;
		int 	move_by;
		char   *txtLeft=NULL, *txtRight=NULL;	/* text from the dialogs */
		XmTextPosition left, right;	/* margins of the selection */
		int lmargin, rmargin, format_width;
		char part_cmd[150];		/* the final part of the command */

		/* check the selection and get the selection positions */
		if(!XmTextGetSelectionPosition(win->edit_text, &left, &right) ||
			left == right)
		{
		    /* popup the error message about non-existent selection */
		    sprintf(work, "%s",  (char *)lstr.flt_no_selection);
		    show_error_message(win, work);
		    break;
		}

		/* get the values from the text widgets; the right margin must
		   be bigger than the left one;
		*/
		txtLeft = (char *)XmTextGetString(win->left_margin);
		txtRight= (char *)XmTextGetString(win->right_margin);

		if(txtLeft != NULL && (strlen(txtLeft) > (size_t)0))
		     lmargin = atoi(txtLeft);
		else lmargin = -1;		/* it means: do NOT set a new left margin */


		if(txtRight != NULL && (strlen(txtRight) > (size_t)0))
		     rmargin = atoi(txtRight);
		else rmargin = -1;

		if(txtRight) XtFree(txtRight);		/* free the memory */
		if(txtLeft)  XtFree(txtLeft);

	        if(lmargin >= 0)
			format_width = rmargin - lmargin;
		else    format_width = rmargin;	
		if(format_width <= 0)
		{
		    /* show the error message; the above check is OK
		       because lmargin and rmargin can't be negative (an
		       appropriate text callback assures this)
		    */
		    if(rmargin >= 0)
		    	show_error_message(win, (char *)lstr.flt_wrong_margins);
		    else
		    	show_error_message(win, (char *)lstr.flt_missing_margins);
		    break;
		}

		/* if we got here all is OK, proceed with action */

		/* start constructing the filter */
		sprintf(work, lstr.expandCmd, win->tabsize);



		if(lmargin >= 0)
		{
		    /* set a new left margin; first delete all leading spaces up to 99 spaces
		       (tabs were transformed to spaces already) (note: sed on SGI let us 254 max in sed),
		       then if lmargin is > 0 insert spaces
		    */
		    sprintf(part_cmd, " | sed 's/^ \\{1,99\\}//' ");   /* delete leading spaces */
		    strcat(work, part_cmd);
			
		    if (lmargin > 0)	/* after formatting move right */
		    {
		        sprintf(part_cmd, " | sed 's/^/%*s/' ",  lmargin, " ");
		        strcat(work, part_cmd);		/* put it together */
		    }
		}

		strcat(work, " | ");
		sprintf(part_cmd, lstr.fmtCmd, format_width);
		strcat(work, part_cmd);
		executeFilterCmd(win, work, lstr.allFormatExt, True);	/* use the common Ext (probably NULL) */

	    }


	    break;

	default:
	    /* an unknown callback type */
	    fprintf (stderr, "Warning: in accept callback\n");
	    break;
    }
    TurnWatchCursor(False);

}   /* DialogOkCB */


/*****************************  DialogApplyCB  ******************************
**
**	Process callbacks from Dialog apply actions.
**	(often this action is equivalent to the No answer !)
*/
#ifdef _NO_PROTO
void DialogApplyCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void DialogApplyCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
{
    char *command;			/* command used in printing */

    int id 		    = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);


    TurnWatchCursor(True);
    switch ( id )
    {
	case DIALOG_SAVE_CHANGES:
	    /* "NO" answer: do not save the current file, simply proceed with
		the action that prompted the save_changes_dialog (first pop
		down the save changes dialog) */
	    XtUnmanageChild (w);
	    switch(win->reason_save_question)
	    {
		case MENU_CLOSE:
		    CloseFile(win);
		    if(aseditWinCount > 1)	remove_asedit_win (win); /* ver. 1.3 close
								causes closing window
								as well (if not the last one) */
		    break;

		case MENU_EXIT:
		    removeWinAndExit(win);
		    break;

		case MENU_SAVE:
		case MENU_SAVE_AS:
		    ;		/* do nothing */
		    break;

		default:
		    /* an unknown reason_save_question */
		    fprintf (stderr, "Warning: an unknown reason_save_question in cancel callback \n");
		    break;
	    }
	    break;

	case DIALOG_FIND_OR_CHANGE:

	    if(win->search_reason == MENU_CHANGE)  /* change all options */
	    {
		win->nextSelectionSearch = False;
		prepare_change_all(win, call_data);

		change_all_found_strings(win, True);

		/* the buttons sensitivity will be restored as a response
		   to a message ending the change all process **/
	    }
	    break;

	case DIALOG_CHANGE_PROMPT:
	    /* skip the replace but continue the search */
	    find_string(win, True);
	    if(win->found_string_start_pos < 0L )
	    {
		XtUnmanageChild(w);
		/* restore the buttons sensitivity */
		set_change_buttons_sensitivity(win, True);
	    }
	    break;

	default:
	    /* an unknown client_data was received and there is no setup to handle this */
	    fprintf (stderr, "Warning: an unknown client_data in apply callback\n");
	    break;

    }
    TurnWatchCursor(False);
} /* DialogApplyCB */


/*****************************  DialogCancelCB  *****************************
**
**	Process callbacks from Dialog cancel actions.
**
**	(because we access that procedure from inside ht_help we didn't declare
**	it as static)
*/
#ifdef _NO_PROTO
void DialogCancelCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void DialogCancelCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
{
    int id 		    = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);

    switch (id)
    {

	case DIALOG_OPEN:
	case DIALOG_SAVE_AS:
	case DIALOG_PRINT_NEW:
	case DIALOG_INSERT:
	case DIALOG_SAVE_CHANGES:
	case QUESTION_OVERWRITE:
	case DIALOG_FIND_OR_CHANGE:
	case DIALOG_GOTOLINE:
	case ERROR_MESSAGE:
	case DIALOG_MOVE_LEFT:
	case DIALOG_MOVE_RIGHT:
	case DIALOG_INDENT_WITH:
	case DIALOG_REFORMAT:
	case DIALOG_FILTER:
	case DIALOG_COMMAND:

	    /* popdown the dialog (important when autoUnmanage set to False ) **/
	    XtUnmanageChild (w);
	    break;

	case HTEXT_HELP:
	    /* unmanage specifically help_dialog widget */
	    XtUnmanageChild( help_dialog);
	    break;

	case DIALOG_CHANGE_PROMPT:
	case QUESTION_CONTINUE_SEARCH:
	case MESSAGE_SEARCH_END:	/* Close option */
	    XtUnmanageChild (w);
	    /* restore the sensitivity of the change buttons */
	    if(!win->nextSelectionSearch)
	    	set_change_buttons_sensitivity(win, True);
	    break;

	default:
	    /* an unknown client_data was received and
	       there is no setup to handle this */
	    fprintf (stderr, "Warning: an unknown client_data in cancel callback\n");
	    break;
    }
} /* DialogCancelCB */


/*****************************  TextCB  *************************************
**
**	Process callbacks from edit_text widget.
**	 i.e. modifyVerifyCallback and motionVerifyCallback
*/
#ifdef _NO_PROTO
void TextCB (w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XtPointer call_data;
#else  /* ! _NO_PROTO */

void TextCB (Widget w, XtPointer client_data, XtPointer call_data)
#endif
{

    XmTextVerifyCallbackStruct  *txt_data = (XmTextVerifyCallbackStruct *) call_data;
    int    reason;		/* reason for the callback */

    int id 		    = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);
    int i;


    reason = txt_data->reason;



    if(reason !=  XmCR_FOCUS && w != win->edit_text) return;

    switch(reason)
    {
	case XmCR_FOCUS:
	   win->edit_text = w;
	   return;


	case XmCR_LOSE_PRIMARY:
	    win->weOwnPrimarySelection = False;
	    XtSetSensitive(win->menu_cut_button,   False);
	    XtSetSensitive(win->menu_copy_button,  False);
	    XtSetSensitive(win->menu_clear_button,   False);
	    for (i=0; i < win->nToolsSelNeeded; i++)
		XtSetSensitive(win->toolsSelNeeded[i], False);


	    return;

	case XmCR_GAIN_PRIMARY:
	    win->weOwnPrimarySelection = True;
	    if(!win->file_read_only)
	    {
		XtSetSensitive(win->menu_cut_button,   True);
		XtSetSensitive(win->menu_clear_button,   True);
	    }
	    else
	    {
		XtSetSensitive(win->menu_cut_button,   False);
		XtSetSensitive(win->menu_clear_button,   False);
	    }
	    XtSetSensitive(win->menu_copy_button,  True);
	    for (i=0; i < win->nToolsSelNeeded; i++)
		XtSetSensitive(win->toolsSelNeeded[i], True);

	    return;

	case XmCR_MODIFYING_TEXT_VALUE:
	    if(win->file_just_loaded)
	    {
		win->file_just_loaded = False;
		win->line = win->column = 1;
		if(win->status_line_on)     /* write the line & column  */
		{
			write_ll(win->line_number,   charset, "%-5ld", win->line);
			write_ll(win->column_number, charset, "%-4ld", win->column);
		}

		return;
	    }
	    /* increase the changes_counter to indicate that the file has been modified
	       and the user should be notified before loading a new one, closing
	       this one, exiting from the program etc.. */
	    if(!win->do_undo_redo_action)
	    {
		if(win->changes_counter < 0L) win->changes_counter = 0L;
		(win->changes_counter) ++;
		if(win->changes_counter == 1L)
		{
		    /* show asterisk changes_status widget */
		    write_ls(win->changes_status, charset, "%s", "*");
		    set_titles_mwindow_icon(win, win->filename, (char *)lstr.changeHint);
		}

	    }

	    break;

	case XmCR_MOVING_INSERT_CURSOR:
	    break;

	default:
	    /* an unknown client_data was received and there is no setup to handle this */
	    fprintf(stderr, "Warning: an unknown client_data in text callback\n");
	    fprintf(stderr,"Detected reason = %d \n", reason);
	    return;
    }


    if(!win->do_undo_redo_action)
	SaveActionForUndo( w, client_data, call_data);  /* save the action for undo */
    win->do_undo_redo_action = False;


    if(win->status_line_on)	/* calculate line & column only when they are shown */
    {

#ifndef _AS_DEBUG	/* Note: this is not a mistake: "ifndef _AS_DEBUG" MUST be here*/

      /* for non-debug version check reason and for Motif 1.2 or higher return;
	 for *debug* version call calc_text_lcn to get some extra information;
	 Note that since 1.3 _AS_DEBUG* is available only in the full version */

      if(XmVersion >= 1002 && reason == XmCR_MODIFYING_TEXT_VALUE) return;
#endif

      calc_text_lcn (w, client_data, call_data); /* calculate line & column */

      write_ll(win->line_number,   charset, "%-5ld", win->line);
      write_ll(win->column_number, charset, "%-4ld", win->column);
    }

} /* TextCB*/


/*****************************  CreateMenus  *********************************
**
**		Create all menus as children of a MenuBar
**		Returns the MenuBar
*/
#ifdef _NO_PROTO
static Widget CreateMenus (win, parent)
	aseditWindowStruct *win;
	Widget parent;
#else  /* ! _NO_PROTO */

static Widget CreateMenus (aseditWindowStruct *win, Widget parent)
#endif
{
	Widget		menu_bar;	/*  RowColumn	 		*/
	Widget		help_button;	/*  cascade help button		*/

	Arg		al[10];		/*  arg list			*/
	register int	ac;		/*  arg count			*/
	int		i, n;




	/*  Create and manage a menu bar (menu area). */
	menu_bar = XmCreateMenuBar(parent, "menuBar", NULL, 0);

	/* change the length of Filter_menu and Command_menu on the basis
	   of the run-time resources; NOTE this HACK is based on the relative
	   position of these menus in the Tools_menu !!!
	*/
	if(lstr.filterNum >= 0  && lstr.filterNum <= 10)
		Tools_menu[FILTERS_MENU_POS].n_sub_items = lstr.filterNum+1;	/* +1 extra item at the top */
	if(lstr.cmdNum >= 0  && lstr.cmdNum <= 10)
		Tools_menu[COMMANDS_MENU_POS].n_sub_items = lstr.cmdNum+1;	/* +1 extra item at the top */



	/* Create the menu from the description */

	as_create_menuh(NULL, menu_bar, Main_menu,
			 XtNumber(Main_menu), charset);

	XtManageChild(menu_bar);

	/* setting the global widgets (they must be accessible from other
	   procedures) to widgets created in the as_create_menuh procedure */
	/*****  watch out to set these properly !!!!! (it's an ugly hack ...) */

        ac = 0;
	win->menu_undo_button  = Edit_menu[ac++].w;
	win->menu_redo_button  = Edit_menu[ac++].w;
	ac++;					/*  separator in the menu */
	win->menu_cut_button   = Edit_menu[ac++].w;
	win->menu_copy_button  = Edit_menu[ac++].w;
	win->menu_paste_button = Edit_menu[ac++].w;
	ac++;					/*  separator ... */
	win->menu_clear_button = Edit_menu[ac++].w;

        ac = 2;
	win->menu_close_button  = File_menu[ac++].w;
	ac++;					/* separator */
	win->menu_save_button   = File_menu[ac++].w;
	win->menu_save_as_button= File_menu[ac++].w;
	ac++;					/* separator */
	win->menu_insert_button  =File_menu[ac++].w;
	win->menu_print_button  = File_menu[ac++].w;

        ac = 0;
	win->menu_find_button  	    =	Search_menu[ac++].w;
	win->menu_find_again_button = 	Search_menu[ac++].w;
	win->menu_replace_button    =	Search_menu[ac++].w;
	win->menu_gotoline_button   = 	Search_menu[ac++].w;
	ac++;					/* separator */
	win->menu_mark_button   = 	Search_menu[ac++].w;
	win->menu_match_button   = 	Search_menu[ac++].w;

	/* another ugly hack to store Tools_menu buttons that need selection !!
	   watch out to NOT go above MAX_SEL_TOOLS;
	*/
	n = ac = 0;
	win->menu_spell_button = Tools_menu[0].w;		/* new in 1.3.2 */
	/* NOT necessary for USE_WHOLE_FILE_OR_SELECTION
		 win->toolsSelNeeded[n++] = Tools_menu[ac++].w;	|* spell *|
	* (changed in 1.3.2 version) */
	ac++;						/* OLD spell that needed selection */
	win->toolsSelNeeded[n++] = Tools_menu[ac++].w;
	ac++;						/* separator */
	win->toolsSelNeeded[n++] = Tools_menu[ac++].w;
	win->toolsSelNeeded[n++] = Tools_menu[ac++].w;
	ac++;						/* separator */
	win->toolsSelNeeded[n++] = Tools_menu[ac++].w;	/* Filters  */

	win->menu_commands_button = Tools_menu[ac++].w;

	if(n > MAX_SEL_TOOLS ) { fprintf(stderr, "\nPlease correct MAX_SET_TOOLS!"); exit (1); }

	win->nToolsSelNeeded = n;	/* set the counter */






	/* store the bookmarks buttons */
	for(i=0; i < TOTAL_MARKS; i++)
	{
	    win->menu_mark_set_button[i] =  Mark_menu_set[i].w;
	    win->menu_mark_go_button[i] =   Mark_menu_go[i].w;
	}
	ResetAllMarks(win);

	/* turn off sensitivity of undo, redo, cut, copy, paste and clear buttons */
	XtSetSensitive(win->menu_undo_button,  False);
	XtSetSensitive(win->menu_redo_button,  False);
	XtSetSensitive(win->menu_cut_button,   False);
	XtSetSensitive(win->menu_copy_button,  False);
	XtSetSensitive(win->menu_paste_button, False);
	XtSetSensitive(win->menu_clear_button, False);

	/* set appropriate file buttons to insensitive */
	XtSetSensitive(win->menu_close_button,   False);
	XtSetSensitive(win->menu_save_button,    False);
	XtSetSensitive(win->menu_save_as_button, False);
	XtSetSensitive(win->menu_insert_button,  False);
	XtSetSensitive(win->menu_print_button,   False);

	/* set all search buttons to insensitive */
	XtSetSensitive(win->menu_find_button,         False);
	XtSetSensitive(win->menu_replace_button,      False);
	XtSetSensitive(win->menu_find_again_button,   False);
	XtSetSensitive(win->menu_gotoline_button,     False);
	XtSetSensitive(win->menu_mark_button,         False);
	XtSetSensitive(win->menu_match_button,        False);


	/* turn off sensitivity of all tools buttons that need selection */
	for (i=0; i < win->nToolsSelNeeded; i++)
		XtSetSensitive(win->toolsSelNeeded[i],False);

	XtSetSensitive(win->menu_spell_button,        	False);
	XtSetSensitive(win->menu_commands_button,        False);
 

	if(lstr.useOldColorSetup)
	{
	    Pixel		background;	/* used for proper set up of mono screens */
	    Pixel		foreground;

	    /* get a colour to be used for editable text widgets; the colour
	       will be the same as a colour of an armed button */
	    ac = 0;
	    XtSetArg(al[ac],  XmNbackground, &background);          ac++;
	    XtSetArg(al[ac],  XmNforeground, &foreground);          ac++;
	    XtSetArg(al[ac],  XmNarmColor, &select_menu_background); 	ac++;
	    XtGetValues(win->menu_find_button, al, ac);
	    /* now check if the select_menu_background is not by chance identical
	       with the background (it happens on mono screens or for a black/white
	       setup); if so do not apply it, but use the standard background.
	     */
	    if(select_menu_background == foreground)
		select_menu_background = background;
	}


	/* create the Help button and help pulldown menu using a predefined
	   structure and my procedure */

	as_create_menuh(NULL, menu_bar, help_Main_menu,
			 XtNumber(help_Main_menu), charset);

	/* setting the help cascade button */
	help_button   = help_Main_menu[0].w;

	ac = 0;
	XtSetArg (al[ac], XmNmenuHelpWidget, help_button);  ac++;
	XtSetValues (menu_bar, al, ac);



	return (menu_bar);
} /* CreateMenus */


#ifdef _NO_PROTO
static void ControlCloseCB(w, client_data, call_data)
    Widget   w;
    XtPointer  client_data, call_data;
#else  /* ! _NO_PROTO */

static void ControlCloseCB(Widget w, XtPointer client_data, XtPointer call_data)
#endif
{
    int id                  = get_id_from_asdat(client_data);
    aseditWindowStruct *win = get_win_from_asdat(client_data);

    if (win->changes_counter != 0L) /* display the 'save' message dialog */
    {
	win->reason_save_question = MENU_CLOSE;
	/* before 1.3	here:       ^^^^^^^^ we used MENU_EXIT */
	show_save_changes_dialog(win);
    }
    else
    {
	CloseFile(win); 		/* close up the file */
	remove_asedit_win (win);
	if(!asedit_last_window)
	{
	    XCloseDisplay(display);
	    exit (0);    		/* exit this program */
	}
    }

}   /* ControlCloseCB */



/*
 * ByeBye - clean up and exit (signal handler !)
 */
#ifdef _NO_PROTO
# ifdef __hpux
    static int ByeBye()
# else
    static void ByeBye()
# endif /* __hpux */
#else  /* ! _NO_PROTO */

# if defined(__STDC__) || defined(vax11c) || defined(__DECC)
    static void ByeBye(int sig)
# else
#   ifdef __hpux
      static int ByeBye(int sig, int code, struct sigcontext *scp, char *adr)
#   else
      static void ByeBye(int sig, int code, struct sigcontext *scp, char *adr)
#   endif  /* __hpux */
# endif /* __STDC__ || vax11c || __DECC */
#endif
{
	aseditWindowStruct *win = asedit_last_window;

	/* exit if there is no file open */

	/*** new version for 1.3 release */

	exitAction(win);


} /* ByeBye */


#include <X11/cursorfont.h>

/****************************	TurnWatchCursor	*****************************
  TurnWatchCursor turns on/off the "watch" cursor over the application
  to provide feedback for the user that he is going to be waiting
  a while before he can intercat with the application again.
*/
#ifdef _NO_PROTO
void TurnWatchCursor(turn_on)
    Boolean turn_on;
#else  /* ! _NO_PROTO */

void TurnWatchCursor(Boolean turn_on)
#endif
{
    static int locked;
    static Cursor cursor;
    XSetWindowAttributes attrs;
    XEvent	event;
    aseditWindowStruct *wc=NULL;    /* current window */

    /* "locked" keeps track if we've already called the function.
       This allows recursion and is necessary for most situations;
    */
    turn_on ? locked++ : locked--;
    if(locked > 1 || ( locked ==1 && turn_on == False ))
		return;		/* already locked and we're not unlocking */

    if(!cursor)		/* if not initialized do it */
	cursor = XCreateFontCursor(display, XC_watch);
    /* if "turn_on" is true, then turn on watch cursor, otherwise, return
       the shell's cursor to normal
    */
    attrs.cursor = turn_on ? cursor : None;
    /* change the main application shell's cursor to the timeout cursor
       (or reset it to normal). Do the same to all other shells except those
       created as XmDIALOG_PRIMARY_APPLICATION_MODAL (the last can't be active
       during such activities that needs setting timeout for the cursor)
    */

    /* DO that for all asedit windows .... */
    wc = asedit_last_window;            /* start from the last */

    if(wc == NULL)  return;             /* sanity check */

    if( (help_dialog) && XtIsRealized(help_dialog))		/* global widget */
	XChangeWindowAttributes(display, XtWindow(help_dialog), CWCursor, &attrs);

    do          /* loop until there is no previous window */
    {
	if(XtIsRealized(wc->topshell))	/* a widget must be realized to have its window */
	    XChangeWindowAttributes(display, XtWindow(wc->topshell), CWCursor, &attrs);

	if( (wc->open_dialog) && XtIsRealized(wc->open_dialog))
	    XChangeWindowAttributes(display, XtWindow(wc->open_dialog), CWCursor, &attrs);
	if( (wc->save_as_dialog) && XtIsRealized(wc->save_as_dialog))
	    XChangeWindowAttributes(display, XtWindow(wc->save_as_dialog), CWCursor, &attrs);
	if( (wc->print_dialog) && XtIsRealized(wc->print_dialog))
	    XChangeWindowAttributes(display, XtWindow(wc->print_dialog), CWCursor, &attrs);
	if( (wc->insert_dialog) && XtIsRealized(wc->insert_dialog))
	    XChangeWindowAttributes(display, XtWindow(wc->insert_dialog), CWCursor, &attrs);
	if( (wc->gotoline_dialog) && XtIsRealized(wc->gotoline_dialog))
	    XChangeWindowAttributes(display, XtWindow(wc->gotoline_dialog), CWCursor, &attrs);
	if( (wc->replace_dialog) && XtIsRealized(wc->replace_dialog))
	    XChangeWindowAttributes(display, XtWindow(wc->replace_dialog), CWCursor, &attrs);
	if( (wc->about_program_message) && XtIsRealized(wc->about_program_message))
	    XChangeWindowAttributes(display, XtWindow(wc->about_program_message), CWCursor, &attrs);

    	XFlush(display);

	wc   = wc->prev;

    } while(wc);

    if(turn_on)
    {	/* we are timing out - in some cases that's the place to put up a
	   a working_dialog to show explicite to the user that he has to wait ...
	*/
	;
    }
    else
    {
	/* get rid of all button and keyboard events that occured during the
	   time out. The user shouldn't have done anything during this time,
	   so flush for button and keypress events. HeyRelease events are not
	   discarded because accelerators require the corresponding release
	   event before normal input can continue.
	*/
	while (XCheckMaskEvent(display, ButtonPressMask | ButtonReleaseMask |
		ButtonMotionMask | PointerMotionMask | KeyPressMask, &event))
	{
		/* do nothing */
	}
	/* if you used a working_dialog you should destroy it now ... */
    }
}   /* TurnWatchCursor */



#ifdef _NO_PROTO
static void set_paste_buttons()
#else  /* ! _NO_PROTO */

static void set_paste_buttons()
#endif
{
    aseditWindowStruct *wc=NULL;    /* current window */

    /* DO that for all asedit windows .... */
    wc = asedit_last_window;            /* start from the last */

    if(wc == NULL)  return;             /* sanity check */

    do          /* loop until there is no previous window */
    {
        /* for read only files && for empty windows the paste button is insensitive */
    	if(!wc->file_read_only && (wc->filename!=NULL)) 
	{
	    XtSetSensitive(wc->menu_paste_button, True);
	    XtSetSensitive(wc->popup_paste_button, True);
	}
        wc   = wc->prev;
    } while(wc);

}   /* set_paste_buttons */



