/* cooledit.c - main file of cooledit
   Copyright (C) 1996, 1997 Paul Sheer

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.
 */

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include "lkeysym.h"

#include "stringtools.h"
#include "coolwidget.h"
#include "edit.h"
#include "editcmddef.h"
#include "loadfile.h"
#include "editoptions.h"
#include "cmdlineopt.h"
#include "shell.h"
#include "igloo.h"
#include "widget/pool.h"

#if HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) (dirent)->d_namlen
#if HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#if HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#if HAVE_NDIR_H
#include <ndir.h>
#endif
#endif
#include "mad.h"

void do_mail (CWidget *edit);

int start_width = 80;
int start_height = 30;

/* error handler */
#ifdef DEBUG
int er_handler (Display * c, XErrorEvent * e)
{
/* NLS ? */
    char err[128];
    XGetErrorText (c, e->error_code, err, 128);
    if (e->request_code == 42)	/* input focus errors are skipped */
	return 0;
    fprintf (stderr, "cooledit: Error detected.\n  %s\n", err);
    fprintf (stderr, "  Protocal request: %d\n", e->request_code);
    fprintf (stderr, "  Resource ID:      0x%x\n", (unsigned int) e->resourceid);
    fprintf (stderr, "Ignoring error.\n");
    return 0;
}
#endif

#if (RETSIGTYPE==void)
#define handler_return return
#else
#define handler_return return 1
#endif

extern Atom ATOM_WM_PROTOCOLS, ATOM_WM_DELETE_WINDOW, ATOM_WM_NAME, ATOM_WM_NORMAL_HINTS;
char *argv_nought = "cooledit";
Window main_window;
int display_dnd_protocol_change_message = 0;

/* {{{ signal handling */

static void main_loop (void);

static RETSIGTYPE userone_handler (int x)
{
    CErrorDialog (main_window, 20, 20, \
/* heads the dialog box for when a SIGUSR1 Signal is recieved: SIGUSR1 */
		  _(" Signal SIGUSR1 Recieved "), 
		_("%s: SIGUSR1 recieved\n" \
	"You may have interrupted Cooledit because a search was taking too\n" \
	"long, or because you executed a recursive macro. In the latter\n" \
	"case, you should exit ASAP. Otherwise, if nothing peculiar was happening\n" \
	"Cooledit is probably still stable. Cooledit will now continue executing"), \
	argv_nought);
    signal (SIGUSR1, userone_handler);
    CEnable ("*");
    XUngrabPointer (CDisplay, CurrentTime);
    main_loop ();		/* continue */
    exit (0);
    handler_return;
}

static RETSIGTYPE quit_handler (int x)
{
/* %s = cooledit */
    fprintf (stderr, _("%s: quiting without saving\n"), argv_nought);
#if 0
    CShutdown ();		/* needed just to close the connection to the display */
#else
    XCloseDisplay (CDisplay);
#endif
    exit (0);
    handler_return;
}

void set_to_kill (pid_t p);

static RETSIGTYPE child_handler (int x)
{
    pid_t p;

    p = waitpid (0, 0, WNOHANG | WUNTRACED);
    set_to_kill (p);
    debug_check (p);

    signal (SIGCHLD, child_handler);
    handler_return;
}

static void set_signals (void)
{
    signal (SIGPIPE, SIG_IGN);
    signal (SIGUSR1, userone_handler);
#if 1
    signal (SIGQUIT, quit_handler);
    signal (SIGINT, quit_handler);
    signal (SIGTERM, quit_handler);
#else
    signal (SIGQUIT, SIG_DFL);
    signal (SIGINT, SIG_DFL);
    signal (SIGTERM, SIG_DFL);
#endif
    signal (SIGCHLD, child_handler);
}

/* }}} signal handling */

/* {{{ NLS support */

struct linguas {
    char *name;
    char *abbr;
} languages[] = {
    {"Chinese", "zh"},
    {"Czech", "cs"},
    {"Danish", "da"},
    {"Dutch", "nl"},
    {"English", "en"},
    {"Esperanto", "eo"},
    {"Finnish", "fi"},
    {"French", "fr"},
    {"German", "de"},
    {"Hungarian", "hu"},
    {"Irish", "ga"},
    {"Italian", "it"},
    {"Indonesian", "id"},
    {"Japanese", "ja"},
    {"Korean", "ko"},
    {"Latin", "la"},
    {"Norwegian", "no"},
    {"Persian", "fa"},
    {"Polish", "pl"},
    {"Portuguese", "pt"},
    {"Russian", "ru"},
    {"Slovenian", "sl"},
    {"Spanish", "es"},
    {"Swedish", "sv"},
    {"Turkish", "tr"}
};


/* }}} NLS support */


/* {{{ hint message on title bar */

void get_next_hint_message (void)
{
    static int i = -1;
    static int n;
    char label[128];
    static char *hints[] =
    {
/* The following are hints that go on the title bar: eg "Cooledit - Hint: Undo key-for-key with Ctrl-Backspace" */
	gettext_noop("To drag and drop, highlight text, then click and drag from within the selection"),
	gettext_noop("Dragging with the right mouse button will move text"),
	gettext_noop("Dragging with the left mouse button will copy text"),
	gettext_noop("Use Shift-Insert to copy text from other applications"),
	gettext_noop("Use Alt-Insert to bring up a history of selected text"),
	gettext_noop("Function keys F11-F20 mean Shift with a function key F1-F10"),
	gettext_noop("Subscribe to or email our mailing list: cooledit@mail.obsidian.co.za"),
	gettext_noop("See how to do regular expression substring replacements in the man page"),
	gettext_noop("Use Shift-Up/Down in input widgets to get a history of inputs"),
	gettext_noop("Run frequently used apps from a hot key: see the Scripts menu"),
	gettext_noop("Get your keypad to work by redefining keys in the Options menu"),
	gettext_noop("Drag a file name from the 'File browser' in the Window menu to insert it"),
	gettext_noop("Use a macro to record repeatedly used key sequences"),
	gettext_noop("Get a list of demo fonts with:  cooledit -font h"),
	gettext_noop("Undo key-for-key with Ctrl-Backspace"),
	gettext_noop("Drag function prototypes and other info from the man page browser"),
	gettext_noop("Double click on words in the man page browser to search for new man pages"),
	gettext_noop("Search for [Options] in  ~/.cedit/.cooledit.ini  and change settings"),
	gettext_noop("Edit the example Scripts to see how to create your own"),
	gettext_noop("Double click on gcc error messages after running Make or Cc"),
	gettext_noop("Turn off these messages from the Options menu: 'Hint time...' = 0"),
	gettext_noop("Email  cooledit@mail.obsidian.co.za  with questions, comments or suggestions"),
	gettext_noop("See how to do regular expression substring replacements in the man page"),
	gettext_noop("See cooledit.1 for a list of the many extended editing/movement keys"),
	gettext_noop("Compose international characters with Right-Control"),
	gettext_noop("Set the LC_ALL and LANG environment variables - see the FAQ"),
	gettext_noop("For new international character support see the FAQ"),
	gettext_noop("Insert (hexa)decimal literals with Control-q and the (hexa)decimal digits"),
	gettext_noop("Try out proportional fonts like Times or Helvetica"),
	gettext_noop("Read all these hint messages in editor/cooledit.c in the source distribution"),
	gettext_noop("See the file INTERNATIONAL for composing international characters"),
	gettext_noop("Edit/move at high speed with the many Ctrl/Meta-Arrow combinations"),
	gettext_noop("Use drag-and-drop to and from input widgets"),
	gettext_noop("Open a file by dragging its name from the 'File browser' onto the background"),
	gettext_noop("Use Shift-Ins to paste into input widgets"),
	gettext_noop("If Cooledit halts, restore by sending SIGUSR1:   kill -1 <pid>"),
	gettext_noop("For fun, hit Ctrl-Shift-Alt-~ to see how text is redrawn"),
	gettext_noop("Turn off the toolbar from the 'Options' menu"),
	gettext_noop("Goto the Python web page: http://www.python.org/"),
	gettext_noop("Disable the 'Window' menu from the 'Options' menu"),
	gettext_noop("If a macro is defined to an unused key, it will execute without having to use Ctrl-A"),
	gettext_noop("Use  smalledit  if you would like a smaller, cut down version of cooledit"),
	gettext_noop("Select *columns* of text by holding the control key down through mouse highlighting"),
	gettext_noop("Use Ctrl-Tab to complete the start of string, C-function or LaTeX-macro"),
	gettext_noop("Turn off tool hints from the Options menu"),
	gettext_noop("Use `Auto paragraph...' and `Word wrap...' to edit paragraphs like a WP"),
	gettext_noop("See how to get a rotating shaded 3D `e' when recieving mail - read coolicon.1"),
	gettext_noop("See how to do regular expression substring replacements in the man page"),
	gettext_noop("Try your hand at adding new Cooledit features with Python"),
	gettext_noop("Mark locations in files with the book mark commands in the Edit menu"),
	gettext_noop("Debug programs with Meta-F5"),
	gettext_noop("Execute explicit debugger commands with Meta-F1"),
	gettext_noop("Turn off spell checking from the Options menu"),
	gettext_noop("File files containing regular expressions with Ctrl-Meta-F"),
	gettext_noop("Delete debugger variables with Del in the variable dialog"),
	gettext_noop("Make a variable watch point by marking it with Ins in the variable dialog"),
	gettext_noop("Change the default size of the undo stack in ~/.cedit/.cooledit.ini")
    };

    if (i < 0) {
	n = sizeof (hints) / sizeof (char *);
	i = time (0) % n;
    } else
	i = (i + 1) % n;

    strcpy (label, _("Cooledit - Hint: "));
    strcat (label, gettext (hints[i]));
    XChangeProperty (CDisplay, main_window, ATOM_WM_NAME, XA_STRING, 8,
		     PropModeReplace, (unsigned char *) label, strlen (label));
}

/* }}} hint message on title bar */


void edit_change_directory (void)
{
    char *new_dir;
    new_dir = CGetDirectory (main_window, 40, 40, current_dir, "", 
/* heads the 'Change Directory' dialog box */
    _(" Change Directory "));
    if (new_dir) {
	if (change_directory (new_dir) < 0) { /* which should never happen */

/* heads the 'Change Directory' dialog box */
	    CErrorDialog(main_window, 20, 20, _(" Change directory "), get_sys_error (_(" Error return from chdir. ")));
	}
    }
}

/* {{{	command-line options */

int load_setup (const char *file);
int save_setup (const char *file);

static char *command_line_files[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

char *editor_options_file = 0;
extern char *option_preferred_visual;
extern int option_force_own_colormap;
extern int option_force_default_colormap;

int option_suppress_load_files = 0;
int option_suppress_load_files_cmdline = 0;
int option_suppress_load_options = 0;
int option_save_setup_on_exit = 0;
int option_hint_messages = 120;
int option_cursor_blink_rate = 7;
int option_pull_down_window_list = 1;
int option_toolbar = 1;
int option_minimal_main_window = 0;
extern char *option_geometry;

int option_new_window_ask_for_file = 1;

char *option_display = 0;
char *option_geometry = 0;
char *option_background_color = "igloo";
char *option_foreground_red = 0;
char *option_foreground_green = 0;
char *option_foreground_blue = 0;
char *option_font = 0;

static int option_command_line_doesnt_override = 0;
static int get_help = 0;
static int get_version = 0;
static int option_verbose = 0;


void usage (void)
{
    printf ( \
/* Translate only the description of what the options does, not the option itself */
	    _("Cooledit version %s\n" \
	    "A user friendly text editor for the X Window System.\n" \
	    "Usage:\n" \
	    "%s [-AabCEhiPsSUVv?] [options] [[+<line>] <file>] [[+<line>] <file>] ...\n"), \
		    VERSION, PACKAGE);
    printf (_("-d, -display <display>                   the X server to display on\n"));
#ifdef GUESS_VISUAL
    printf (_("-vis, --visual <visual-class>            use   cooledit -vis h   for help\n" \
	    "-C, -cmap, --own-colormap                force use of own colormap\n" \
	    "-defcmap, --default-colormap             force use of default colormap\n"));
#endif
    printf (_("-g, -geom, -geometry <geometry>          window size and position\n" \
	    "-m, --minimal-main-window                main window border only\n" \
	    "-lines <n>                               number of text lines\n" \
	    "-columns <n>                             number of text columns\n" \
	    "-bg, --background-color <color>          eg blue for solid blue, default: igloo\n" \
	    "-R, --foreground-red <value>             red component, default: 0.9\n" \
	    "-G, --foreground-green <value>           green component, default: 1.1\n" \
	    "-B, --foreground-blue <value>            blue component, default: 1.4\n" \
	    "-f, -fn, -font <font-name>               use   cooledit -font h   for help\n" \
	    "-S, --suppress-load-files                don't load saved desktop\n" \
	    "-U, --suppress-load-options              don't load saved options\n" \
	    "-E, -no-override                         command line doesn't override init file\n" \
	    "-I, --use-initialisation-file <file>     default: ~/.cedit/.cooledit.ini\n" \
	    "-wordwrap, --word-wrap <length>          default: 72\n" \
	    "-typew, --type-writer                    type-writer word wrap\n" \
	    "-autop, --auto-paragraph                 word processor paragraphing\n" \
	    "-i, --all-characters                     display characters outside of locale\n" \
	    "-noi --no-international-characters       default\n" \
	    "-t, -tab, --tab-spacing <spacing>        set tab spacing\n" \
	    "-s, -space, --space-filled-tabs          fill tabs with ascii 32 (a space)\n" \
	    "-nospace, --no-space-filled-tabs         default\n" \
	    "-a, --auto-indent                        return does an auto indent (default)\n" \
	    "-noautoi, --no-auto-indent               turn off auto indent\n" \
	    "-b, --backspace-through-tabs             backspace deletes to right margin\n" \
	    "-noback, --no-backspace-through-tabs     default\n" \
	    "-half, --fake-half-tabs                  emulate half tabs with spaces (default)\n" \
	    "-no-half, --no-fake-half-tabs            turn off half tabbing\n" \
	    "-toolbar                                 edit windows have a toolbar\n" \
	    "-no-toolbar                              disabled\n" \
	    "-A, -save-setup                          save setup on exit\n" \
	    "-P, -no-save-setup                       don't save setup on exit\n" \
	    "-W, --whole-chars-search <chars>         characters that constitute a whole word\n" \
	    "                            when searching, default: 0-9a-z_ (typed out in full)\n" \
	    "-w, --whole-chars-move <chars>           characters that constitute a whole word\n" \
	    "         when moving and deleting, default: 0-9a-z_; ,[](){} (typed out in full)\n" \
	    "-verbose                                 print details of initialisation\n" \
	    "-h, -H, -?, --help                       print this message to stdout\n" \
	    "-V, -v, --version                        print versiom info\n" \
	    "\n"));
}

void version (void)
{
    printf (_("Cooledit version %s\n"), VERSION);
}

#if 0

struct prog_options {
    char char_opt;
    char *short_opt;
    char *long_opt;
    int type;			/* one of the #define's above */
    char **str;			/* pointer to a single string */
    char **strs;		/* pointer to an array of strings */
    void *option;		/* an integer or double */
#if 0
    char *dummy_opt;		/* for the help text */
    char *help;			/* help line */
#endif
};

#endif

struct prog_options cooledit_options[] =
{
    {' ', "", "", ARG_STRINGS, 0, command_line_files, 0},
    {0, "-bg", "--background-color", ARG_STRING, &option_background_color, 0, 0},
#ifdef GUESS_VISUAL
    {0, "-vis", "--visual", ARG_STRING, &option_preferred_visual, 0, 0},
    {'C', "-cmap", "--own-colormap",  ARG_SET, 0, 0, &option_force_own_colormap},
    {0, "-defcmap", "--default-colormap",  ARG_SET, 0, 0, &option_force_default_colormap},
#endif
    {0, "", "-toolbar", ARG_SET, 0, 0, &option_toolbar},
    {0, "", "-no-toolbar", ARG_CLEAR, 0, 0, &option_toolbar},
    {'R', "", "--foreground-red", ARG_STRING, &option_foreground_red, 0, 0},
    {'G', "", "--foreground-green", ARG_STRING, &option_foreground_green, 0, 0},
    {'B', "", "--foreground-blue", ARG_STRING, &option_foreground_blue, 0, 0},
    {'f', "-fn", "-font", ARG_STRING, &option_font, 0, 0},
    {'S', "", "--suppress-load-files", ARG_SET, 0, 0, &option_suppress_load_files_cmdline},
    {'U', "", "--suppress-load-options", ARG_SET, 0, 0, &option_suppress_load_options},
    {'E', "-no-override", "", ARG_SET, 0, 0, &option_command_line_doesnt_override},
    {'I', "", "--use-initialisation-file", ARG_STRING, &editor_options_file, 0, 0},
    {'i', "", "--all-characters", ARG_SET, 0, 0, &option_international_characters},
    {0, "-wordwrap", "--word-wrap", ARG_INT, 0, 0, &option_word_wrap_line_length},
    {0, "-typew", "--type-writer", ARG_SET, 0, 0, &option_typewriter_wrap},
    {0, "-autop", "--auto-paragraph", ARG_SET, 0, 0, &option_auto_para_formatting},
    {0, "-noi", "--no-international-characters", ARG_CLEAR, 0, 0, &option_international_characters},
    {'t', "-tab", "--tab-spacing", ARG_INT, 0, 0, &option_tab_spacing},
    {'s', "-space", "--space-filled-tabs", ARG_SET, 0, 0, &option_fill_tabs_with_spaces},
    {0, "-nospace", "--no-space-filled-tabs", ARG_CLEAR, 0, 0, &option_fill_tabs_with_spaces},
    {'a', "-autoi", "--auto-indent", ARG_SET, 0, 0, &option_return_does_auto_indent},
    {0, "-noautoi", "--no-auto-indent", ARG_CLEAR, 0, 0, &option_return_does_auto_indent},
    {'b', "", "--backspace-through-tabs", ARG_SET, 0, 0, &option_backspace_through_tabs},
    {0, "-noback", "--no-backspace-through-tabs", ARG_CLEAR, 0, 0, &option_backspace_through_tabs},
    {0, "-half", "--fake-half-tabs", ARG_SET, 0, 0, &option_fake_half_tabs},
    {0, "-no-half", "--no-fake-half-tabs", ARG_CLEAR, 0, 0, &option_fake_half_tabs},
    {'A', "-save-setup", "", ARG_SET, 0, 0, &option_save_setup_on_exit},
    {'P', "-no-save-setup", "", ARG_CLEAR, 0, 0, &option_save_setup_on_exit},
    {'W', "", "--whole-chars-search", ARG_STRING, &option_whole_chars_search, 0, 0},
    {'w', "", "--whole-chars-move", ARG_STRING, &option_chars_move_whole_word, 0, 0},
    {'h', "-?", "--help", ARG_SET, 0, 0, &get_help},
    {'H', "-help", "--help", ARG_SET, 0, 0, &get_help},
    {'V', "-v", "--version", ARG_SET, 0, 0, &get_version},
    {0, "", "-verbose", ARG_SET, 0, 0, &option_verbose},
    {'d', "", "-display", ARG_STRING, &option_display, 0, 0},
    {'g', "-geom", "-geometry", ARG_STRING, &option_geometry, 0, 0},
    {0, "-lines", "", ARG_INT, 0, 0, &start_height},
    {0, "-columns", "", ARG_INT, 0, 0, &start_width},
    {'m', "--minimal-main-window", "", ARG_SET, 0, 0, &option_minimal_main_window},
    {0, 0, 0, 0, 0, 0, 0}
};

static void process_command_line (int argc, char **argv)
{
    int error;
    error = get_cmdline_options (argc, argv, cooledit_options);

    if (error) {
	fprintf (stderr, _("%s: error processing commandline argument %d\n"), argv[0], error);
	usage();
	exit (1);
    }

    if (get_help)
	usage();
    if (get_version)
	version();
    if (get_help || get_version)
	exit (0);

}


/* }}}	command-line options */


/* {{{  multiple edit windows */

/* maximum number of edit windows: */
#define N_EDIT 50

/* the editors (a stack of sorts) */
CWidget *edit[N_EDIT] = {0, 0};

int current_edit = 0;		/* containing the focus */
int last_edit = 0;		/* number of editors open */



/* }}}  multiple edit windows */

/* from menu.c: */
void destroy_menu (CWidget * w);
void render_menu (CWidget * w);

/* local: */
void update_wlist (void);
void wlist_callback (unsigned long ignored);
int new_editor (int number, int x, int y, int columns, int lines, char *f, char *d,...);
int write_config (int clean);
void current_to_top (void);

/* {{{ process make (and other shell) error message */

/* returns -1 on not found and line numbner = -1. Could return only one as -1 */
int get_file_and_line_from_error (char *message, int *line_number, char **new_file)
{
    int i, l;
    char *p;

    if (!last_edit)
	return 0;

    *line_number = -1;

    for (i = 0; message[i]; i++)
	if ((l = strspn (message + i, "0123456789")))
	    if (message[i + l] == ':' && message[i - 1] == ':') {
		*line_number = atoi (message + i);
		break;
	    }
    for (i = 0; message[i]; i++)
	if ((l = strspn (message + i, "0123456789")))
	    if (strchr (":;\",\n ", message[i + l]) && message[i - 1] == ':') {
		*line_number = atoi (message + i);
		break;
	    }
    for (i = 0; message[i]; i++)
	if ((l = strspn (message + i, "0123456789")))
	    if (strchr (":;\",\n ", message[i + l]) && strchr (":;\", ", message[i - 1])) {
		*line_number = atoi (message + i);
		break;
	    }
    if (!strncmp (message, "/", 1) || !strncmp (message, "./", 2))
	goto try_new;
    p = strrchr (message, ' ');
    if (p) {
	p++;
	if (!strncmp (p, "/", 1) || !strncmp (p, "./", 2)) {
	    char m[MAX_PATH_LEN], *c;
	    message = p;
	  try_new:
	    memset (m, 0, MAX_PATH_LEN);
	    if (!strncmp (message, "./", 2)) {
		getcwd (m, MAX_PATH_LEN - 1);
		c = strchr (message, ':');
		if (!c)
		    c = message + strlen (message);
		strncpy (m + strlen (m), message + 1, (unsigned long) c - (unsigned long) (message + 1));
	    } else {
		c = strchr (message, ':');
		if (c) {
		    if ((unsigned long) c > (unsigned long) message) {
			if (*(c - 1) == ')') {
			    char *q;
			    for (q = c - 2; (unsigned long) q > (unsigned long) message; q--)
				if (*q == '(') {
				    c = q;
				    break;
				}
			}
		    }
		} else {
		    c = message + strlen (message);
		}
		strncpy (m, message, (unsigned long) c - (unsigned long) message);
	    }
	    c = canonicalize_pathname (m);
	    for (i = 0; i < last_edit; i++)
		if (edit[i]->editor->filename)
		    if (*(edit[i]->editor->filename)) {
			char q[MAX_PATH_LEN];
			strcpy (q, edit[i]->editor->dir);
			if (q[strlen (q) - 1] == '/')
			    q[strlen (q) - 1] = '\0';
			strcat (q, "/");
			strcat (q, edit[i]->editor->filename);
			if (!strcmp (c, q)) {
			    free (c);
			    return i;
			}
		    }
	    if (new_file)
		*new_file = c;
	    return -1;
	}
    }
    for (i = 0; i < last_edit; i++)
	if (edit[i]->editor->filename)
	    if (*(edit[i]->editor->filename)) {
		p = strstr (message, edit[i]->editor->filename);
		if (!p)
		    continue;
/* now test if this is a whole word */
		if ((unsigned long) p > (unsigned long) message)
		    if (strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789.", *(p - 1)))
			continue;
		if (strchr ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789.", p[strlen (edit[i]->editor->filename)]))
		    continue;
		return i;
	    }
    return -1;
}

int new_file_callback (char *full_file_name,...);

void edit_move_to_line_easy (WEdit *e, int l)
{
    edit_move_to_line (e, l - 1);
    if (edit_count_lines (e, e->start_display, e->curs1) < e->num_widget_lines / 4)
	edit_move_display (e, l - e->num_widget_lines / 4 - 1);
    else if (edit_count_lines (e, e->start_display, e->curs1) > e->num_widget_lines * 3 / 4)
	edit_move_display (e, l - e->num_widget_lines * 3 / 4 - 1);
    e->force |= REDRAW_PAGE;
}

int goto_error (char *message, int raise_wm_window)
{
    int ed, l;
    char *new_file = 0;
    ed = get_file_and_line_from_error (message, &l, &new_file);
    if (new_file) {
	if (!new_file_callback (new_file)) {
	    edit_move_to_line_easy (edit[current_edit]->editor, l);
	    if (raise_wm_window)
		CRaiseWMWindow ("cooledit");
	    free (new_file);
	    return 0;
	}
	free (new_file);
	return 1;
    } else if (ed >= 0 && l >= 0) {
	current_edit = ed;
	edit_move_to_line_easy (edit[current_edit]->editor, l);
	edit[ed]->editor->force |= REDRAW_COMPLETELY;
	CFocus (edit[ed]);
	XRaiseWindow (CDisplay, edit[current_edit]->parentid);
	CRaiseWindows ();
	if (raise_wm_window)
	    CRaiseWMWindow ("cooledit");
	current_to_top ();
    }
    return 0;
}

static int bookmarks_select_callback (CWidget * w, XEvent * x, CEvent * c)
{
    if (c->double_click || (c->command == CK_Enter && !c->handled)) {
	int width;
	char *q;
	width = w->options & TEXTBOX_WRAP ? (w->width - TEXTBOX_BDR) / FONT_MEAN_WIDTH : 32000;
	q = strline (w->text, strmovelines (w->text, w->current, w->cursor - w->firstline, width));
	CDestroyWidget ("bookmarks");
	edit[current_edit]->editor->force |= REDRAW_COMPLETELY;
	goto_error (q, 1);
    }
    if (c->command == CK_Cancel) {
	CDestroyWidget ("bookmarks");
	edit[current_edit]->editor->force |= REDRAW_COMPLETELY;
    }
    return 0;
}

static int bookmarks_done_callback (CWidget * w, XEvent * x, CEvent * c)
{
    CDestroyWidget ("bookmarks");
    return 1;
}

void goto_file_dialog (char *heading, char *tool_hint, char *text)
{
    int x, y;
    Window win;
    CWidget *w;
    if (CIdent ("bookmarks"))
	return;
    win = CDrawHeadedDialog ("bookmarks", main_window, 20, 20, heading);
    CIdent ("bookmarks")->position = WINDOW_ALWAYS_RAISED;
    CGetHintPos (&x, &y);
    w = CDrawTextbox ("bookmarks.text", win, x, y, 70 * FONT_MEAN_WIDTH + EDIT_FRAME_W, 20 * FONT_PIX_PER_LINE + EDIT_FRAME_H, 0, 0, text, TEXTBOX_NO_STRDUP);
    if (tool_hint)
	CSetToolHint ("bookmarks.text", tool_hint);
    w->position |= POSITION_HEIGHT | POSITION_WIDTH;
    (CIdent ("bookmarks.text.vsc"))->position |= POSITION_HEIGHT | POSITION_RIGHT;
    CGetHintPos (0, &y);
    (CDrawPixmapButton ("bookmarks.done", win, 0, y, PIXMAP_BUTTON_CROSS))->position = POSITION_BOTTOM | POSITION_CENTRE;
    CCentre ("bookmarks.done");
    CSetSizeHintPos ("bookmarks");
    CSetWindowResizable ("bookmarks", FONT_MEAN_WIDTH * 15, FONT_PIX_PER_LINE * 15, 1600, 1200);
    CMapDialog ("bookmarks");
    CAddCallback ("bookmarks.text", bookmarks_select_callback);
    CAddCallback ("bookmarks.done", bookmarks_done_callback);
    CFocus (CIdent ("bookmarks.text"));
}

void bookmark_select (void)
{
    int i;
    POOL *p;
    p = pool_init ();
/* get all bookmarks */
    for (i = 0; i < last_edit; i++) {
	struct _book_mark *b;
	if (!edit[i]->editor->book_mark)
	    continue;
	for (b = edit[i]->editor->book_mark; b->prev; b = b->prev);	/* rewind */
	for (; b; b = b->next)
	    if (b->line >= 0)
		pool_printf (p, "%s%s:%d\n", edit[i]->editor->dir, edit[i]->editor->filename, b->line + 1);
    }
    pool_null (p);
    goto_file_dialog (_ (" Select Bookmark "), _ ("Double click on a bookmark to goto the file and line number"), (char *) pool_break (p));
}

/* }}} process make (and other shell) error message */

/* {{{  window stack manipulation */

/* moves the current editor to the top of the stack */
void current_to_top (void)
{
    CWidget *w = edit[current_edit];
    memmove (&(edit[1]), &(edit[0]), current_edit * sizeof (CWidget *));
    edit[0] = w;
    current_edit = 0;
    CSetEditMenu (w->ident);	/* sets the editor to which the menu will send commands */
    update_wlist ();
}

int extents_width = 0, extents_height = 0;

#include "bitmap/toolbar.bitmap"

int toolbar_cmd[NUM_TOOL_BUTTONS] =
{
    CK_Maximize,
    CK_Exit,
    CK_Util,
    CK_Save,
    CK_Load,
    CK_XCut,
    CK_XStore,
    CK_XPaste,
    CK_Find,
    CK_Mail,
    0
};

static char *toolbar_hints[NUM_TOOL_BUTTONS] =
{
/* Toolhint */
    gettext_noop ("Maximise the window, Alt-F6"),
    gettext_noop ("Close this edit window, F10"),
    gettext_noop ("Filetype specific utilities menu, Meta-U, Alt-U"),
    gettext_noop ("Save this edit buffer, F2"),
    gettext_noop ("Load new file, Ctrl-O"),
    gettext_noop ("Delete, and copy to X clipboard, Shift-Del"),
    gettext_noop ("Copy to X clipboard, Ctrl-Ins"),
    gettext_noop ("Paste from X clipboard, Shift-Ins"),
    gettext_noop ("Search for text, F7"),
    gettext_noop ("Mail edit buffer"),
    gettext_noop ("Open the cooledit man page")
};

int tool_bar_callback (CWidget * w, XEvent * xe, CEvent * ce)
{
    XEvent e;
    char ident[32], *p;
    strcpy (ident, ce->ident);
    p = strchr (ident, '.');
    *p = 0;
    memset (&e, 0, sizeof (XEvent));
    e.type = EditorCommand;
    e.xkey.keycode = toolbar_cmd[w->cursor];
    e.xkey.window = (CIdent (ident))->winid;
    CSendEvent (&e);
    return 1;
}

void edit_man_cooledit (unsigned long ignored);

int help_callback (CWidget * w, XEvent * xe, CEvent * ce)
{
    edit_man_cooledit (0);
    return 1;
}

#define VERT_TEXT_OFFSET 7

int render_vert_text (CWidget * w)
{
    CWidget *wdt;
    wdt = CIdent (w->ident + 3);
    if (!wdt)
	return 0;
    if (!wdt->editor)
	return 0;
    if (!wdt->editor->syntax_type)
	return 0;
    CSetColor (color_palette (1));
    XDrawVericalString8x16 (CDisplay, w->winid, CGC, VERT_TEXT_OFFSET, NUM_TOOL_BUTTONS * 25 + 12,
	    wdt->editor->syntax_type, strlen (wdt->editor->syntax_type));
    return 1;
}

void change_syntax_type (CWidget * edi)
{
    CWidget *w;
    char x[34];
#ifdef HAVE_PYTHON
    XEvent e;
    memset (&e, 0, sizeof (XEvent));
    e.type = EditorCommand;
    e.xkey.keycode = CK_Type_Load_Python;
    e.xkey.window = edi->winid;
    CSendEvent (&e);
#endif
    strcpy (x, "win");
    strcat (x, edi->ident);
    w = CIdent (x);
    if (!w)
	return;
    CSetColor (COLOR_FLAT);
    CRectangle (w->winid, VERT_TEXT_OFFSET, NUM_TOOL_BUTTONS * 25 + 12, 16, 1024);
    CSendExpose (w->winid, VERT_TEXT_OFFSET, NUM_TOOL_BUTTONS * 25 + 12, 16, 1024);
}

int draw_vert_text (CWidget * w, XEvent * xe, CEvent * ce)
{
    if (xe->type == Expose) {
	if (xe->xexpose.x > VERT_TEXT_OFFSET + 16)
	    return 0;
	return render_vert_text (w);
    }
    return 0;
}

#define NEW_WINDOW_FROM_TEXT ((char *) 1)

/* creates a new editor at 'number' in the stack and shifts up the stack */
/* returns one on success, 0 on error: usually file not found */
int new_editor (int number, int x, int y, int columns, int lines, char *f, char *d,...)
{
    static int edit_count = 0;
    int xe, ye;
    int i, modified = 0;
    CWidget *new_edit;
    Window win;
    char *t = 0, *p, *q;
    unsigned long size;

    if (last_edit >= N_EDIT) {
	CErrorDialog (0, 0, 0, _ (" Error "), _ (" You have opened the maximum number of possible edit windows "));
	return 0;
    }
    edit_count++;
    if (f == NEW_WINDOW_FROM_TEXT) {
	va_list ap;
	va_start (ap, d);
	t = va_arg (ap, char *);
	size = va_arg (ap, unsigned long);
	f = 0;
	va_end (ap);
	modified = 1;
    } else {
	size = 0;
	if (!d)
	    d = "";
	if (!f) {
	    f = 0;
	    t = "";
	} else if (!*f) {
	    f = 0;
	    t = "";
	} else if (!*d && *f != '/')
	    d = catstrs (current_dir, "/", 0);
    }
    q = catstrs ("editor", itoa (edit_count), 0);
    win = CDrawDialog (p = catstrs ("wineditor", itoa (edit_count), 0), main_window, x, y);

    CGetHintPos (&xe, &ye);
    if (option_toolbar) {
	for (i = 0; i < NUM_TOOL_BUTTONS; i++) {
	    CWidget *w;
	    w = CDrawPixmapButton (catstrs (q, ".B", itoa (i), 0), win,
			3, ye + i * 25, 25, 25, toolbar_buttons[i], '0');
	    if (toolbar_cmd[i] == CK_Util) {
		CDrawMenuButton (catstrs (q, ".util", 0), w->winid, main_window,
		     25 + 10, -65, AUTO_SIZE, 0, _ (" Utility "), 0, 0, 0, 0);
	    }
	    w->takes_focus = 0;
	    w->cursor = i;	/* just to easily identify the button */
	    CAddCallback (w->ident, tool_bar_callback);
	    CSetToolHint (w->ident, _ (toolbar_hints[i]));
	}
/* man page "help" */
	CAddCallback (catstrs (q, ".B", itoa (NUM_TOOL_BUTTONS - 1), 0), help_callback);
	CSetToolHint (catstrs (q, ".B", itoa (NUM_TOOL_BUTTONS - 1), 0), _ (toolbar_hints[NUM_TOOL_BUTTONS - 1]));
	xe = 25 + 4;
    }
    edit_set_syntax_change_callback (change_syntax_type);
    reset_hint_pos (0, 0);
    new_edit = CDrawEditor (q, win, xe, ye, columns * FONT_MEAN_WIDTH,
			    lines * FONT_PIX_PER_LINE, t, f, d, EDITOR_HORIZ_SCROLL, size);
    if (!new_edit) {
	CDestroyWidget (catstrs ("wineditor", itoa (edit_count), 0));
	return 0;
    }
    new_edit->position |= (POSITION_WIDTH | POSITION_HEIGHT);
    new_edit->editor->modified = modified;

    CSetSizeHintPos (p);
    CSetWindowResizable (p, 150, 150, 1600, 1200);
    CMapDialog (p);
    CAddBeforeCallback (p, draw_vert_text);

    x = x + (CIdent (p))->width;
    y = y + (CIdent (p))->height;
    extents_width = max (x, extents_width);
    extents_height = max (y, extents_height);

    (CIdent (catstrs (q, ".text", 0)))->position |= (POSITION_BOTTOM | POSITION_WIDTH);
    (CIdent (catstrs (q, ".vsc", 0)))->position |= (POSITION_RIGHT | POSITION_HEIGHT);
    (CIdent (catstrs (q, ".hsc", 0)))->position |= (POSITION_BOTTOM | POSITION_WIDTH);

    memmove (&(edit[number + 1]), &(edit[number]), (last_edit - number) * sizeof (CWidget *));
    last_edit++;
    edit[last_edit] = 0;
    edit[number] = new_edit;
    update_wlist ();
    return 1;
}


/* removes the editor at 'current_edit' */
void remove_current (int do_raise)
{
    CDestroyWidget (CWidgetOfWindow (edit[current_edit]->parentid)->ident);
    /* close up the hole in the stack: */
    memmove (&(edit[current_edit]), &(edit[current_edit + 1]), (last_edit - current_edit) * sizeof (CWidget *));
    /* one less editor: */
    last_edit--;
    edit[last_edit] = 0;
    if (last_edit) {
	if (current_edit == last_edit)
	    current_edit--;
	CFocus (edit[current_edit]);	/* focus on the next */
	if (do_raise) {
	    XRaiseWindow (CDisplay, edit[current_edit]->parentid);
	    CRaiseWindows ();
	}
    }
    update_wlist ();
}

/* }}}  window stack manipulation */

void get_main_window_size (unsigned int *width, unsigned int *height)
{
    Window root;
    int x, y;
    unsigned int border, depth;
    XGetGeometry (CDisplay, main_window, &root, \
		  &x, &y, width, height, &border, &depth);
}

/* {{{  'Window' menu call backs */

/* returns -1 if not, number of editor if yes */
int file_is_open (char *p)
{
    char s[MAX_PATH_LEN];
    int r = -1, i;
    p = canonicalize_pathname (p);
    for (i = 0; i < last_edit && r >= 0; i++) {
	char *t;
	strcpy (s, edit[i]->editor->dir);
	strcat (s, "/");
	strcat (s, edit[i]->editor->filename);
	t = canonicalize_pathname (s);
	if (!strcmp (t, p))
	    r = i;
	free (t);
    }
    free (p);
    return r;
}

static int height_offset;

void fit_into_main_window (int *lines, int *columns, int x, int y)
{
    unsigned int width, height;
    get_main_window_size (&width, &height);
    while (*columns * FONT_MEAN_WIDTH + 25 + EDIT_FRAME_W + 4 + 2 + 20 + WIDGET_SPACING * 2> width - x)
	(*columns)--;
    if (*columns * FONT_MEAN_WIDTH < 150)
	(*columns) = 150 / FONT_MEAN_WIDTH;
    while ((*lines + 1) * FONT_PIX_PER_LINE + EDIT_FRAME_H + WIDGET_SPACING * 3 + 8 + TEXT_RELIEF * 2 + 3 + 3 + 3 > height - y)
	(*lines)--;
    if (*lines * FONT_PIX_PER_LINE < 250)
	*lines = 250 / FONT_PIX_PER_LINE;
}

/* returns non-zero on error */
int new_file_callback (char *full_file_name,...)
{
    int x, y, columns, lines, result = 1;
    char *d = 0;

    if (!full_file_name || full_file_name == NEW_WINDOW_FROM_TEXT) {
	if (last_edit)
	    /* copy the current directory: */
	    d = (char *) strdup (edit[current_edit]->editor->dir);
	else
	    d = (char *) strdup (home_dir);
    } else {
	if (file_is_open (full_file_name) >= 0)
	    if (CQueryDialog (main_window, 20, 20, _ (" Open "), _ (" A file by this name is already open, \n Continue open? "), _ (" Continue "), _ (" Cancel "), 0))
		return 0;
    }

    CGetWindowPosition (edit[current_edit]->parentid, main_window, &x, &y);
    if (last_edit) {
	columns = edit[current_edit]->editor->num_widget_columns;
	lines = edit[current_edit]->editor->num_widget_lines;
    } else {
	columns = 200;
	lines = 100;
    }
    lines -= 2;

    fit_into_main_window (&lines, &columns, x, y);

    if (full_file_name == NEW_WINDOW_FROM_TEXT) {
	char *t;
	unsigned long size;
	va_list ap;
	va_start (ap, full_file_name);
	t = va_arg (ap, char *);
	size = va_arg (ap, unsigned long);
	x = new_editor (0, x, y, columns, lines, NEW_WINDOW_FROM_TEXT, d, t, size);
	va_end (ap);
    } else {
	x = new_editor (0, x, y, columns, lines, full_file_name, d);
    }
    if (x) {
	current_edit = 0;
	CFocus (edit[current_edit]);
	result = 0;
    }
    if (d)
	free (d);
    return result;
}

void new_window_callback (unsigned long ignored)
{
    char *f = 0;
    if (option_new_window_ask_for_file)
	f = CGetLoadFile (main_window, 20, 20, edit[current_edit]->editor->dir, "", _(" Open "));
    new_file_callback (f);
    if (f)
	free (f);
}

void window_cycle_callback (unsigned long ignored)
{
    current_edit = (current_edit + 1) % last_edit;
    CFocus (edit[current_edit]);
    XRaiseWindow (CDisplay, edit[current_edit]->parentid);
    CRaiseWindows ();		/* brings ALWAYS_ON_TOP windows to the top */
    update_wlist ();
}

void save_desk_callback (unsigned long ignored)
{
    write_config (0);
}

char *get_all_lists (void);
void free_all_lists (void);
void free_all_scripts (void);
void put_all_lists (char *list);
void complete_command (CWidget * e);

void exit_app (unsigned long save)
{
    char *p;
    switch ((int) save) {
    case 0:
	break;
    case 1:
	if (write_config (1))
	    return;		/* saves all and tries to exit all editors */
	break;
    case 2:
	if (write_config (2))
	    return;		/* tries to exit all editors */
	break;
    }
    if (option_save_setup_on_exit)
	save_setup (editor_options_file);
    save_options_section (editor_options_file, "[Input Histories]", p = get_all_lists ());
    free (p);
    free_all_scripts ();
    complete_command (0);
    debug_shut ();
#ifdef HAVE_PYTHON
    coolpython_shut ();
#endif
    CShutdown ();
    if (editor_options_file)
	free (editor_options_file);
    CDisable (0);
    free (argv_nought);
    free_all_lists ();
    load_setup (0);
    catstrs_clean ();
#if HAVE_MAD
/* NLS ? */
    fprintf (stderr, "cooledit: calling mad_finalise(),\n");
    mad_finalize (__FILE__, __LINE__);
#endif
    exit (0);
}

/* number of 'Window' menu items */
#define WLIST_ITEMS 9

void add_to_focus_stack (Window w);

/* a file was selected in the menu, so focus and raise it */
void wlist_callback (unsigned long ignored)
{
    current_edit = CIdent ("menu.wlist")->current - WLIST_ITEMS;
    current_to_top ();
    XRaiseWindow (CDisplay, edit[current_edit]->parentid);
    CRaiseWindows ();
    add_to_focus_stack (edit[current_edit]->winid);
}

void close_window_callback (unsigned long ignored)
{
    CEditMenuCommand (CK_Exit);
}

void menu_browse_cmd (unsigned long ignored)
{
    int l;
    for (l = 0;; l++)
	if (!CIdent (catstrs ("_cfileBr", itoa (l), 0)))
	    break;
    CDrawBrowser (catstrs ("_cfileBr", itoa (l), 0), CRoot, 0, 0, current_dir, "", _(" File Browser "));
    (CIdent (catstrs ("_cfileBr", itoa (l), 0)))->position |= WINDOW_UNMOVEABLE;
}

extern char *init_font;
extern char *init_bg_color;

void run_main_callback (unsigned long ignored)
{
    char lines[10], columns[10];
    sprintf (lines, "%d", edit[current_edit]->editor->num_widget_lines);
    sprintf (columns, "%d", edit[current_edit]->editor->num_widget_columns);
    switch (fork()) {
	case 0:
	    set_signal_handlers_to_default ();
	    execlp (argv_nought, argv_nought, "-Smf", init_font, "-lines", lines, "-columns", columns, 0);
	    exit (0);
	case -1:
	    CErrorDialog (0, 0, 0, _(" Run 'cooledit' "), get_sys_error (_(" Error trying to fork process ")));
	    return;
	default:
	    return;
    }
}

/* }}}  'Window' menu call backs */

/* {{{  'Window' menu update */


void init_usual_items (struct menu_item *m)
{
    m[0].text = (char *) strdup (_(" New window\tC-F3 "));
    m[0].hot_key = '~';
    m[0].call_back = new_window_callback;

    m[1].text = (char *) strdup (_(" New main window\tF13 "));
    m[1].hot_key = '~';
    m[1].call_back = run_main_callback;

    m[2].text = (char *) strdup (_(" Window cycle\tC-F6/S-Tab "));
    m[2].hot_key = '~';
    m[2].call_back = window_cycle_callback;

    m[3].text = (char *) strdup (_(" Close window\tF10 "));
    m[3].hot_key = '~';
    m[3].call_back = close_window_callback;

    m[4].text = (char *) strdup (_(" Close all and exit\tC-F10 "));
    m[4].hot_key = '~';
    m[4].call_back = exit_app;
    m[4].data = 1;

    m[5].text = (char *) strdup (_(" Save all and exit\tM-x "));
    m[5].hot_key = '~';
    m[5].call_back = exit_app;
    m[5].data = 2;

    m[6].text = (char *) strdup (_(" Save desktop\tC-F2 "));
    m[6].hot_key = '~';
    m[6].call_back = save_desk_callback;
    
    m[7].text = (char *) strdup (_(" File browser...\t"));
    m[7].hot_key = '~';
    m[7].call_back = menu_browse_cmd;

    m[WLIST_ITEMS - 1].text = (char *) strdup ("  ");
    m[WLIST_ITEMS - 1].hot_key = 0;
    m[WLIST_ITEMS - 1].call_back = 0;
}


void update_wlist (void)
{
    struct menu_item *m;
    CWidget *w;
    int i;

    w = CIdent ("menu.wlist");

    destroy_menu (w);

    m = CMalloc ((last_edit + WLIST_ITEMS) * sizeof (struct menu_item));

    init_usual_items (m);

    if (last_edit > 0) {
	for (i = 0; i < last_edit; i++) {
	    m[i + WLIST_ITEMS].text = (char *) strdup (catstrs (" ", edit[i]->editor->filename, "  ", 0));
	    m[i + WLIST_ITEMS].hot_key = 0;
	    m[i + WLIST_ITEMS].call_back = wlist_callback;
	    if (i == current_edit)
		m[i + WLIST_ITEMS].text[0] = '>';
	}
    }
    w->numlines = last_edit + WLIST_ITEMS;
    w->current = current_edit + WLIST_ITEMS;
    while (w->current >= w->numlines)
	w->current--;
    w->menu = m;

    if (w->droppedmenu != 0) {
	w->droppedmenu->menu = m;
	w->droppedmenu->numlines = w->numlines;
	w->droppedmenu->current = w->current;
	render_menu (w->droppedmenu);
    }
    if (last_edit > 0)
	CSetEditMenu (edit[current_edit]->ident);
}

/* }}}  'Window' menu update */


/* {{{ configuration file handler */

void edit_about_cmd (void);

/* open all the files listed in the configuration file returns 0 on success */
int read_config (void)
{
    char f[256];
    char d[512];
    char *s, *r;
    long w, h, c, l;
    float x, y;
    int n = 0, num_read = 0, i;
    DIR *dir;
    dir = opendir (catstrs (home_dir, EDIT_DIR, "/.t", 0));
    s = get_options_section (editor_options_file, "[Files]");
    if (!dir && errno == ENOENT && !s) {
	char *str;
	char mail_command[256];
	edit_about_cmd ();
#ifdef HAVE_PYTHON
#define HAVE_PYTHON_VERSION "p"
#else
#define HAVE_PYTHON_VERSION ""
#endif
	str = catstrs (_ (" \n" \
		     " Cooledit will now mail the following message \n" \
			  " to count the number of cooledit users: \n"), \
		       " \n" \
		       " >\n" \
		       " > Cooledit-" VERSION HAVE_PYTHON_VERSION " automatic mail message: \n" \
		       " > I am running on a " TARGET_MACHINE " \n" \
		       " >\n", 0);
#ifndef DISABLE_AUTO_MAIL
	if (
	       CQueryDialog (0, 0, 0, _ (" Mail me "), str, _ (" OK "), _ (" Cancel "), 0) == 0) {
	    sprintf (mail_command, "/bin/sh -c 'echo \"Cooledit-" VERSION HAVE_PYTHON_VERSION " automatic mail message:\n" \
		   "I am running on a " TARGET_MACHINE "\n.\n\004\n\" " \
		     "| mail psheer@obsidian.co.za " \
		     "> /dev/null'"
		);
	    CSystem (mail_command);
	} else {
	    exit (0);
	}
#endif
    }
    if (!dir) {
	mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
	mkdir (catstrs (home_dir, EDIT_DIR, "/.t", 0), 0700);
    }
    if (dir)
	closedir (dir);
    if (!s)
	return 1;
    r = s;
    for (;;) {
	n = 0;
	i = sscanf (s, "%[^ ] %[^ ] x=%f y=%f columns=%ld lines=%ld cursor=%ld topline=%ld %n", d, f, &x, &y, &w, &h, &c, &l, &n);
	s += n;
	if (i < 3)
	    break;
	if (i != 8) {
	    CErrorDialog (main_window, 20, 20, _ (" Load Config "), _ (" Error in initialisation file %s: line %d "), editor_options_file, num_read + 1);
	    free (r);
	    return 1;
	}
	x = x * (float) FONT_MEAN_WIDTH + 0.5;
	y = y * (float) FONT_PIX_PER_LINE + 0.5;
	if (new_editor (num_read, (int) x, (int) y, w, h, f, d)) {
	    edit_move_display (edit[num_read]->editor, l);
	    edit_move_to_line (edit[num_read]->editor, c);
	    num_read++;
	}
	if (!n)
	    break;
    }

    current_edit = 0;
    for (i = last_edit - 1; i >= 0; i--)
	XRaiseWindow (CDisplay, edit[i]->parentid);

    CRaiseWindows ();
    update_wlist ();
    free (r);
    return 0;
}


/* format a line for the config file of the current editor */
void print_stuff (char *s)
{
    CWidget *w;
    w = CWidgetOfWindow (edit[current_edit]->parentid);
    *s = 0;
    if (edit[current_edit])
	if (edit[current_edit]->editor->filename && edit[current_edit]->editor->dir)
	    if (*(edit[current_edit]->editor->filename) && *(edit[current_edit]->editor->dir))
		sprintf (s, "%s %s x=%f y=%f columns=%d lines=%d cursor=%ld topline=%ld\n",
			 edit[current_edit]->editor->dir,
			 edit[current_edit]->editor->filename,
			 (float) w->x / (float) FONT_MEAN_WIDTH, (float) w->y / (float) FONT_PIX_PER_LINE, edit[current_edit]->editor->num_widget_columns, edit[current_edit]->editor->num_widget_lines,
			 edit[current_edit]->editor->curs_line,
			 edit[current_edit]->editor->start_line);
}

/* returns 0 on success. Returns 1 on fail and 2 on user cancel */
/* write out the config file. clean = 1: also tries to exit each file. */
/* clean = 2: saves every file before trying to exit. */
int write_config (int clean)
{
    char *f, *t;
    int result = 0;
    char s[1024];
    t = f = CMalloc (65536);
    *f = 0;
    current_to_top ();
    current_edit = 0;
    do {
	print_stuff (s);
	if (clean) {
	    if (edit[current_edit]->editor->modified)
		XRaiseWindow (CDisplay, edit[current_edit]->parentid);
	    if (clean == 2 && edit[current_edit]->editor->modified)
		edit_execute_command (edit[current_edit]->editor, CK_Save, -1);
	    edit_execute_command (edit[current_edit]->editor, CK_Exit, -1);
	    if (edit[current_edit]->editor->stopped == 1) {
		int ce = current_edit;
		print_stuff (s);	/* user may have changed the filename on exit */
		remove_current (0);
		current_edit = ce;
	    } else {
		result = 2;
		print_stuff (s);
		current_edit++;
	    }
	} else {
	    current_edit++;
	}
	if (*s) {
	    sprintf (f, s);
	    f += strlen (s);
	    *f = 0;
	}
    } while (current_edit < last_edit);

/* restack: */
    current_edit = last_edit - 1;
    while (current_edit >= 0) {
	XRaiseWindow (CDisplay, edit[current_edit]->parentid);
	current_edit--;
    };

    current_edit = 0;
    CRaiseWindows ();
    if (save_options_section (editor_options_file, "[Files]", t))
	CErrorDialog (main_window, 20, 20, _(" Save desktop "), get_sys_error (_(" Error trying to save file ")));
    free (t);
    update_wlist ();
    return result;
}

/* }} configuration file handler */

#ifdef HAVE_DND
/* {{ */

/*
   If a filename is dropped onto the main window, open an edit
   window with that file.
 */
int open_drop_file (XEvent * xevent, CEvent * cwevent)
{
    unsigned char *data;
    unsigned long size;
    int data_type, xs, ys;
    if (xevent->xany.type != ClientMessage)
	return 0;
    if (xevent->xany.window != main_window)
	return 0;
    data_type = CGetDrop (xevent, &data, &size, &xs, &ys);

    if (data_type == DndNotDnd)
	return 0;
    if (data_type == DndFile) {
	new_file_callback ((char *) data);
    } else {
	if (data_type == DndFiles) {
	    unsigned long i = size;
	    while (i--)
		data[i] = data[i] ? data[i] : '\n';
	} else if (data_type != DndRawData && data_type != DndText) {	/* we are going to allow nulls in DndText */
	    size = strnlen ((char *) data, size);
	}
	new_file_callback (NEW_WINDOW_FROM_TEXT, data, size);
    }
    if (data)
	free (data);
    return 1;
}

#else

static struct drop {
    unsigned char *data;
    int size;
    Atom type;
} drop = {

    0, 0, 0
};

static int handle_drop (CWidget * w, Window from, unsigned char *data, int size, int xs, int ys, Atom type, Atom action)
{
    if (drop.data)
	free (drop.data);
    drop.data = CMalloc (size + 1);
    memcpy (drop.data, data, size);
    drop.size = size;
    drop.data[size] = '\0';
    drop.type = type;
    return 0;
}

/*
   If a filename is dropped onto the main window, open an edit
   window with that file.
 */
char *filename_from_url (char *data, int size, int i);

static void open_drop_file (unsigned char *data, int size, Atom type)
{
    if (type == XInternAtom (CDisplay, "url/url", False)) {
	if (!strncmp ((char *) data, "file:", 5)) {
	    char *f;
	    f = filename_from_url ((char *) data, size, strlen ("file:"));
	    new_file_callback (f);
	    free (f);
	} else {
	    new_file_callback (NEW_WINDOW_FROM_TEXT, data, size);
	}
    } else {
	new_file_callback (NEW_WINDOW_FROM_TEXT, data, size);
    }
    return;
}

/* }} */
#endif

char *get_full_filename (const char *f)
{
    char *s, *p;

    if (*f == '/')
	return (char *) f;

    s = malloc (2048);
    if (getcwd (s, 2000)) {
	p = (char *) strdup (catstrs (s, "/", f, 0));
	free (s);
	return p;
    }
    free (s);
    return 0;
}

int editors_modified (void)
{
    int i, r = 0;
    for (i = 0; i < last_edit; i++)
	r |= edit[i]->editor->modified;
    return r;
}

static void cooledit_init (void)
{
    CInitData cooledit_startup;

    memset (&cooledit_startup, 0, sizeof (cooledit_startup));

    cooledit_startup.name = argv_nought;
    cooledit_startup.geometry = option_geometry;
    cooledit_startup.display = option_display;
    cooledit_startup.font = option_font;
    cooledit_startup.bg = option_background_color;
    cooledit_startup.fg_red = option_foreground_red;
    cooledit_startup.fg_green = option_foreground_green;
    cooledit_startup.fg_blue = option_foreground_blue;

    if (option_verbose)
	cooledit_startup.options = CINIT_OPTION_VERBOSE;

/* initialise: */
    CInitialise (&cooledit_startup);
}

#define DEFAULT_INI_FILE home_dir, "/.cedit/.cooledit.ini"
void get_home_dir (void);
void CDrawCooleditMenuButtons (Window parent, int x, int y);
extern int user_defined_key (unsigned int state, unsigned int keycode, KeySym keysym);
extern void execute_script (WEdit * e, int i);
#ifdef HAVE_PYTHON
extern void coolpython_command (WEdit * e, int i);
#endif
int is_focus_prev_key (KeySym k, int command, unsigned int state);

static int initial_columns, initial_lines;
static CEvent cooledit_cevent;
static XEvent cooledit_xevent;

#define approx_equ(a,b) (((a) < (b) + FONT_HEIGHT) && (a) > (b) - FONT_HEIGHT)

static int similar_size_to_main_window (CWidget * w)
{
    if (approx_equ (w->width, CIdent ("cooledit")->width) &&
      approx_equ (w->height, CIdent ("cooledit")->height - height_offset)
	&& approx_equ (w->x, 0) && approx_equ (w->y, height_offset))
	return 1;
    return 0;
}

static void maximise_window (char *ident)
{
    CWidget *w;
    int lines, columns;
    unsigned int wm, hm;
    char x[34];
    strcpy (x, "win");
    strcat (x, ident);
    get_main_window_size (&wm, &hm);
    lines = hm / FONT_PIX_PER_LINE;
    columns = wm / FONT_MEAN_WIDTH;
    fit_into_main_window (&lines, &columns, 0, height_offset);
    CSetWidgetSize (x, columns * FONT_MEAN_WIDTH + 25 + EDIT_FRAME_W + 4 + 2 + 20 + WIDGET_SPACING * 2,
		    (lines + 1) * FONT_PIX_PER_LINE + EDIT_FRAME_H + WIDGET_SPACING * 3 + 8 + TEXT_RELIEF * 2 + 3 + 3 + 3);
    w = CIdent (x);
    CSetWidgetPosition (x, (wm - w->width) / 2, height_offset + (hm - height_offset - w->height) / 2);
}

void debug_key_command (int command);

/* ----main_loop()--------------------------------------------------------- */

static void main_loop (void)
{
    for (;;) {
	CNextEvent (&cooledit_xevent, &cooledit_cevent);
	if (cooledit_xevent.type == TickEvent) {
	    debug_callback ();
	    continue;
	}
	if (cooledit_xevent.type == Expose || !cooledit_xevent.type
	    || cooledit_xevent.type == InternalExpose)
	    continue;
	switch (cooledit_xevent.type) {
	case AlarmEvent:{
		static int hint_count = 0;
		if (option_hint_messages)
		    if (!((hint_count++) % (CGetCursorBlinkRate () * option_hint_messages)))
			get_next_hint_message ();
		break;
	    }
	case EditorCommand:	/* send by us to the library */
	case KeyPress:
	    if (cooledit_cevent.handled)
		break;
	    if (cooledit_cevent.kind == C_EDITOR_WIDGET || cooledit_cevent.kind == C_MENU_BUTTON_WIDGET || !last_edit) {
		switch ((int) cooledit_cevent.command) {
		case CK_Complete:
		    complete_command (edit[current_edit]);
		    break;
		case CK_Find_File:
		    find_file ();
		    break;
		case CK_Ctags:
		    ctags ();
		    break;
		case CK_Mail:
		    do_mail (edit[current_edit]);
		    break;
		case CK_Save_Desktop:
		    save_desk_callback (0);
		    write_config (0);	/* tries to exit all editors */
		    if (option_pull_down_window_list)
			CPullDown (CIdent ("menu.wlist"));
		    break;
		case CK_New_Window:
		    new_window_callback (0);
		    if (option_pull_down_window_list)
			CPullDown (CIdent ("menu.wlist"));
		    break;
		case CK_Menu:
		    break;
		default:
		    if (cooledit_cevent.command >= 350 && cooledit_cevent.command < 400)
			debug_key_command (cooledit_cevent.command);
		    else if (is_focus_prev_key (cooledit_cevent.key, cooledit_cevent.command, cooledit_xevent.xkey.state) ||
			cooledit_cevent.command == CK_Cycle) {
			window_cycle_callback (0);
			if (option_pull_down_window_list)
			    CPullDown (CIdent ("menu.wlist"));
		    } else {
			CPullUp (CIdent ("menu.wlist"));
		    }
		    break;
		}
		if (cooledit_cevent.kind != C_MENU_BUTTON_WIDGET) {
		    switch ((int) cooledit_cevent.command) {
		    case CK_Menu:	/* pull down the menu */
			CMenuSelectionDialog (CGetLastMenu ());
			break;
		    case CK_Check_Save_And_Quit:	/* save desktop and quit all */
			exit_app (1);
			break;
		    case CK_Run_Another:	/* new editor window */
			run_main_callback (0);
			break;
		    case CK_Save_And_Quit:
			exit_app (2);
			break;
		    }
		    break;
		}
	    }
	    break;
	    /* when you release the ctrl key, the window must go to the top of the list */
#ifdef HAVE_DND
	case ClientMessage:
	    open_drop_file (&cooledit_xevent, &cooledit_cevent);
	    break;
#endif
	case KeyRelease:
	    if (cooledit_cevent.handled)
		break;
	    if (cooledit_cevent.kind == C_EDITOR_WIDGET)
		if (mod_type_key (CKeySym (&cooledit_xevent))) {
		    current_to_top ();
		    CPullUp (CIdent ("menu.wlist"));
		}
	    break;
	    /* if you click on an edit window, it must go to the top, so... */
	case ButtonRelease:
	    if (cooledit_cevent.kind == C_WINDOW_WIDGET) {
		CWidget *w;
		w = CIdent (cooledit_cevent.ident);
		if (!w)
		    break;
		if (similar_size_to_main_window(w))
		    w->position |= POSITION_HEIGHT | POSITION_WIDTH;
		else
		    w->position &= ~(POSITION_HEIGHT | POSITION_WIDTH);
	    }
	    break;
	case ButtonPress:
	    if (cooledit_cevent.kind == C_EDITOR_WIDGET) {
		int i;
		/* find which one was clicked on: */
		for (i = 0; i < last_edit; i++)
		    if (edit[i]->winid == cooledit_cevent.window) {
			current_edit = i;
			break;
		    }
		XRaiseWindow (CDisplay, edit[current_edit]->parentid);
		CRaiseWindows ();
		current_to_top ();
	    }
	    break;
	}
	if (cooledit_xevent.type == QuitApplication) {
	    if (!editors_modified ()) {
		exit_app (0);
	    } else {
		int i;
		i = CQueryDialog (0, 0, 0,
				  _ (" Quit "), _ (" Quit Cooledit ? "), _ (" Cancel quit "), _ (" Quit and save all "),
				  _ (" Quit, do not save "), 0);
		switch (i) {
		case 0:

		    break;
		case 1:
		    exit_app (2);
		    break;
		case 2:
		    exit_app (0);
		    break;
		}
	    }
	    continue;
	}
	if (cooledit_cevent.command) {
	    switch ((int) cooledit_cevent.command) {
#ifdef HAVE_PYTHON
	    case CK_Type_Load_Python:
		coolpython_typechange (cooledit_cevent.window);
		break;
#endif
	    case CK_Util:
		CMenuSelectionDialog (CIdent (catstrs (edit[current_edit]->ident, ".util", 0)));
		break;
	    case CK_Load:
	    case CK_New:
	    case CK_Save_As:
		update_wlist ();
		break;
	    case CK_Man_Page:
		edit_man_page_cmd (CGetEditMenu ()->editor);
		break;
	    case CK_Maximize:
		maximise_window (cooledit_cevent.ident);
		break;
	    }
	}
	/* if an editor has been exitted out of, it must be destroyed: */
	if (last_edit) {
	    if (edit[current_edit]->editor->stopped == 1) {
		char *d;
		d = (char *) strdup (edit[current_edit]->editor->dir);
		remove_current (1);
		if (!last_edit) {
		    initial_lines = 100;
		    initial_columns = 200;
		    fit_into_main_window (&initial_lines, &initial_columns, 0, height_offset);
		    new_editor (0, 0, height_offset, initial_columns, initial_lines, 0, d);
		    CFocus (edit[current_edit]);
		}
		update_wlist ();
		free (d);
	    }
	}
	if (CDndClass->stage == XDND_DROP_STAGE_IDLE && drop.data) {
	    open_drop_file (drop.data, drop.size, drop.type);
	    free (drop.data);
	    drop.data = 0;
	}
    }
}

static void custom_keys (WEdit * e, int i)
{
    if (i < MAX_NUM_SCRIPTS)
	execute_script (e, i);
#ifdef HAVE_PYTHON
    else
	coolpython_command (e, i - MAX_NUM_SCRIPTS);
#endif
}

static char *mime_majors[3] =
{"url", "text", 0};

/* main window only recieves drops, so... */
static struct mouse_funcs main_mouse_funcs =
{
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    (int (*)(void *, Window, unsigned char *, int, int, int, Atom, Atom)) handle_drop,
    0,
    DndText,
    mime_majors
};


/* ----main()-------------------------------------------------------------- */
int main (int argc, char **argv)
{
    Window buttonwin;
    CWidget *w;
    int x, y, setsize = 0;
    char *example_fonts[] =
    {
	"-misc-fixed-bold-r-normal--13-120-75-75-c-80-iso8859-1",
	"-adobe-courier-medium-r-normal--13-120-75-75-m-60-iso8859-1",
	"-*-times-medium-r-*--14-*-*-*-p-*-iso8859-1",
	"-*-helvetica-bold-r-*--14-*-*-*-p-*-iso8859-1",
	"-*-charter-bold-r-*--14-*-*-*-p-*-iso8859-1",
	"-*-times-medium-r-*--20-*-*-*-p-*-iso8859-1",
	"-*-helvetica-bold-r-*--20-*-*-*-p-*-iso8859-1",
	"-*-charter-bold-r-*--20-*-*-*-p-*-iso8859-1",
	"-*-*-bold-*-normal--10-100-75-75-c-80-iso8859-1",
	"-*-*-bold-r-normal--12-120-75-75-c-80-iso8859-1",
	"-*-*-bold-r-normal-*-15-*-*-*-c-*-iso8859-1"
    };
    int n;

    setlocale (LC_CTYPE, "");
    setlocale (LC_TIME, "");
    setlocale (LC_MESSAGES, "");
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);

    n = sizeof (example_fonts) / sizeof (char *);

    argv_nought = (char *) strdup (argv[0]);

    process_command_line (argc, argv);

    if (option_font)
	if (!strcmp (option_font, "?") || !strcmp (option_font, "h")
	 || !strcmp (option_font, "-?") || !strcmp (option_font, "-h")) {
	    int i;
	    printf (_ ("Examples: \n"));
	    for (i = 0; i < n; i++)
		printf ("cooledit -font '%s'\n", example_fonts[i]);
	    printf ("cooledit -font default\n" \
		    "cooledit -font 8x13bold\n" \
		    "cooledit -font 1-%d\n", n);
	    exit (1);
	}
    get_home_dir ();
    if (!editor_options_file)
	editor_options_file = (char *) strdup (catstrs (DEFAULT_INI_FILE, 0));

    if (!option_suppress_load_options) {
	char *p;
	load_setup (editor_options_file);
	put_all_lists (p = get_options_section (editor_options_file, "[Input Histories]"));
	if (p)
	    free (p);
    }
    if (option_minimal_main_window)
	option_geometry = 0;
    if (!option_command_line_doesnt_override)
	process_command_line (argc, argv);
    if (option_font)
	if (!strcmp (option_font, "default"))
	    option_font = (char *) strdup ("8x13bold");
    if (option_font)
	if (strspn (option_font, "0123456789") == strlen (option_font)) {
	    int i;
	    i = atoi (option_font);
	    if (i < 1 || i > n) {
		printf (_ ("Allowable range is 1 to %d\n"), n);
		exit (1);
	    }
	    option_font = (char *) strdup (example_fonts[i - 1]);
	}
    initial_columns = start_width;
    initial_lines = start_height;

    cooledit_init ();
    main_window = CDrawMainWindow ("cooledit", "Cooledit");
    xdnd_set_dnd_aware (CDndClass, main_window, 0);
    if (display_dnd_protocol_change_message) {
	CMessageDialog (CRoot, 0, 0, 0, _("Cooledit Note"),
			_("Cooledit has detected the option \"option_dnd_version\" in your\n" \
			"user initialisation file ~/.cedit/.cooledit.ini under the section\n" \
			"[Options]. This means you are upgrading from a version prior to\n" \
			"3.7.0. Versions after 3.6.3 no longer support the Dnd protocol.\n" \
	 "Only the XDND protocol is supported (version 0 through 2).\n" \
			"Some minor behavioural changes will be evident. In particular,\n" \
			"Coolicon drop scripts will NO LONGER WORK and should be rewritten\n" \
	 "to take advantage of the XDND MIME data types. Consult the\n" \
			"cooledit(1) and coolicon(1) man pages and the FAQ for further info.\n"));
    }
    w = CWidgetOfWindow (main_window);
    w->funcs = mouse_funcs_new (w, &main_mouse_funcs);

    if (!strcasecmp (init_bg_color, "igloo"))
	CSetBackgroundPixmap ("cooledit", igloo_data, 220, 156, 'A');

    load_keys (editor_options_file);

#ifdef DEBUG
    XSetErrorHandler (er_handler);
#endif

/* draw window for the menubuttons to go on: */
    buttonwin = CDrawDialog ("menu", main_window, 0, 0);
/* this window must never be below anything: */
    CIdent ("menu")->position = WINDOW_ALWAYS_RAISED;
    CGetHintPos (&x, &y);
    CDrawMenuButton ("menu.wlist", buttonwin, main_window,
/* Title of the 'Window' pull down menu */
		     x, y, AUTO_SIZE, 1, _ (" Window "),
		     _ (" New window\tC-F3 "), 0, 0, 0);
/* Toolhint for the 'Window' menu button */
    CSetToolHint ("menu.wlist", _ ("Manipulating the desktop"));
    CGetHintPos (&x, 0);
    CDrawEditMenuButtons ("menu", buttonwin, main_window, x, y);
    CGetHintPos (&x, 0);
    CDrawCooleditMenuButtons (buttonwin, x, y);

    CSetSizeHintPos ("menu");
    CMapDialog ("menu");
    height_offset = (CIdent ("menu"))->height + (CIdent ("menu"))->y;

    if (!option_suppress_load_files && !option_suppress_load_files_cmdline)
	read_config ();

    edit_set_user_key_function (user_defined_key);
    edit_set_user_command (custom_keys);
#ifdef HAVE_PYTHON
/* this must be done before loading files */
    coolpython_init (argc, argv);
#endif
    debug_init ();

    if (command_line_files[0]) {
	int i;
	char *q;
	long l = 0, num_read = 0;
	for (i = 0; command_line_files[i]; i++) {
	    if (command_line_files[i][0] == '+') {
		l = atoi (command_line_files[i] + 1) - 1;
		if (l < 0)
		    l = 0;
		continue;
	    }
	    q = get_full_filename (command_line_files[i]);
#if 0
	    fit_into_main_window (&initial_lines, &initial_columns, 0, height_offset);
#endif
	    if (new_editor (num_read, 0, height_offset, initial_columns, initial_lines, command_line_files[i], 0)) {
		edit_move_display (edit[num_read]->editor, l);
		edit_move_to_line (edit[num_read]->editor, l);
		num_read++;
	    }
	    l = 0;
	}
	if (edit[0])
	    XRaiseWindow (CDisplay, edit[0]->parentid);
	CRaiseWindows ();
	update_wlist ();
    }
    if (!last_edit) {
/* no windows are open (no config initial_lines or commandline files so) */
#if 0
	if (w->options & WINDOW_USER_SIZE)
	    initial_lines = initial_columns = 200;
	fit_into_main_window (&initial_lines, &initial_columns, 0, height_offset);
#endif
	new_editor (0, 0, height_offset, initial_columns, initial_lines, 0, current_dir ? current_dir : home_dir);
	current_edit = 0;
	update_wlist ();
	setsize = 1;
    }

    CSetEditMenu (edit[0]->ident);
    CSetLastMenu (CIdent ("menu.wlist"));
    current_to_top ();

    CSetCursorBlinkRate (option_cursor_blink_rate);

    load_scripts ();
    update_script_menu_items ();

    set_signals ();

    CFocus (edit[current_edit]);

    if (setsize || !(w->options & WINDOW_USER_SIZE))	/* this means that the size was specified by the user in 'geometry' */
	CSetWidgetSize ("cooledit", extents_width, extents_height);

    CSetWindowResizable ("cooledit", 300, 300, 20000, 20000);
/* Toolhint */
    CSetToolHint ("cooledit", _ ("Drop a filename or text onto this space"));

    CMapDialog ("cooledit");

    for (n = 0; n < last_edit; n++) {
	char p[32];
	strcpy (p, "win");
	strcat (p, edit[n]->ident);
	w = CIdent (p);
	if (!w)
	    continue;
	if (similar_size_to_main_window (w))
	    w->position |= POSITION_HEIGHT | POSITION_WIDTH;
	else
	    w->position &= ~(POSITION_HEIGHT | POSITION_WIDTH);
    }
    main_loop ();
    return 0;
}

