/*  Tilem, TI-Linux Emulator
 *  Copyright (C) 2001 Solignac Julien <x1cygnus@xcalc.org>
 *  Portions copyright (C) 2004 Benjamin Moody <benjamin@ecg.mit.edu>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "../../../config.h"

#include<gdk/gdkkeysyms.h>
#include<sys/types.h>
#include<gtk/gtk.h>
#include<string.h>
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>


#include "debug.h"
/* >>> dependencies */
#include "../core/Z80.h"
#include "../core/dep/inter.h"
/* dependencies <<< */


/* >>> Imported */
#include "../dasm.h"
#include "../symbols.h"
#include "outils.h"
#include "files.h"
#include "menus.h"
/* Imported <<< */


/* >>> Globals */
/* char statmess[40]; */
byte writestk = 0;

/* unsigned short *lstpc; */
byte listlen = 64/*11*/;
unsigned short lstpc[64/*12*/];
int trace_pos;

G_LOCK_DEFINE(traps);
int trap_want_db = 0;
int trap_want_save = 0;
/* Globals <<< */


/* >>> Private */
struct debuginfo {
	int disass_row;
	GtkWidget *dasm;
	GtkWidget *regl[12], *hexcode, *stkcode;
};

typedef void (*ptrfunc) (unsigned short, unsigned short, gpointer);

static unsigned short getreg(byte i);
static void setreg(byte i, unsigned short v);
static void create_hexbox(char *title, char *label, char *value, char maxlen, ptrfunc func, unsigned short data, gpointer data2);

static void dostep(void);
static void create_bpdiag(void);
static void setpc(GtkObject *debugw);
static void gotopc(GtkObject *debugw);
static void loadsym(GtkWidget *widget);
static void clearbpx(GtkWidget *widget);
static void clearsyms(GtkWidget *widget);
static void refreshstk(GtkWidget *stkcode);
static void create_bpxset(GtkObject *bpdiag);
static void setpctoselection(GtkObject *debugw);
static void refreshhex(GtkWidget *hexcode, word hexloc);
static void setbpx(GtkWidget *widget, GtkObject *debugw);
static void stepovr(GtkWidget *widget, GtkObject *debugw);
static void tracebk(GtkWidget *widget, GtkObject *debugw);
static void tracefwd(GtkWidget *widget, GtkObject *debugw);
static void reficons(byte sel, struct debuginfo *debugdat);
static gint debugend(GtkWidget *widget, gpointer debugw, gpointer data);
/* Private <<< */


/* >>> Resources */
static GtkItemFactoryEntry codemenu[] = {
			{"/Goto...", "G", setpc, 0, NULL},
			{"/Goto PC", NULL, gotopc, 0, NULL},
			{"/Set PC to Selection", NULL, setpctoselection, 0, NULL},
			{"/---", NULL, NULL, 0, "<Separator>"},
			{"/Load symbols", NULL, loadsym, 0, NULL},
			{"/Clear symbols", NULL, clearsyms, 0, NULL},
			{"/---", NULL, NULL, 0, "<Separator>"},
			{"/Toggle Breakpoint", "F2", setbpx, 0, NULL},
			{"/Handle Breakpoints", NULL, create_bpdiag, 0, NULL},
			{"/Clear all breakpoints", NULL, clearbpx, 0, NULL},
			{"/---", NULL, NULL, 0, "<Separator>"},
			{"/Trace Backward", NULL, tracebk, 0, NULL},
			{"/Trace Forward", NULL, tracefwd, 0, NULL},
			{"/---", NULL, NULL, 0, "<Separator>"},
			{"/Step Over", "F8", stepovr, 0, NULL},
			{"/Step", "F7", dostep, 0, NULL},
			{"/Run", "F5", GTK_SIGNAL_FUNC(debugend), 0, NULL}
};

static char *rlabels[12] = {"AF", "HL", "DE", "BC", "PC", "IY", "AF'", "HL'", "DE'", "BC'", "SP ", "IX "};
/* Resources <<< */


/* >>> Static */
	/* >>> Breakpoints */
static void clearbpx(GtkWidget *widget)
{
	extern byte numbp;

	numbp = 0;
	reficons(0, (struct debuginfo*) gtk_object_get_user_data(GTK_OBJECT(widget)));
}


static void setbpx(GtkWidget *widget, GtkObject *debugw)
{
	extern struct wbplist bpdat[maxbp];
	extern byte numbp;

	struct debuginfo *debugdat;
	gchar *text, *endp;
	unsigned short x;
	byte i, z;

	if (!(debugw))
		debugw = GTK_OBJECT(widget);

	debugdat = (struct debuginfo *) gtk_object_get_user_data(debugw);

	gtk_clist_get_text(GTK_CLIST(debugdat->dasm), debugdat->disass_row, 1, &text);
	x = (unsigned short) strtol(text, &endp, 16);
	if ((*endp != '\0') || (*text == '\0')) return;

	for (i = 0; i < numbp; i++) {
		if ((bpdat[i].addr_to == x) && (bpdat[i].addr_from == x) && (bpdat[i].type == BPTYPE_X)) {
			for (z = i; z < maxbp - 1; z++)
				bpdat[z] = bpdat[z + 1];
			numbp--;
			reficons(0, debugdat);
			return;
		}
	}

	if (numbp == maxbp) {
		fprintf(stderr, "** max breakpoints exceeded **\n");
		return;
	}

	bpdat[numbp].type = BPTYPE_X;
	bpdat[numbp].addr_to = bpdat[numbp].addr_from = x;
	numbp++;
	reficons(0, debugdat);
}


static void ref_bplist(GtkCList *bplist)
{
	extern struct wbplist bpdat[maxbp];
	extern byte numbp;

	char str[100], *inptr;
	byte i, actype;

	inptr = str;
	gtk_clist_clear(bplist);
	for (i = 0; i < numbp; i++) {

		strcpy(str, "BP");
		actype = bpdat[i].type;
		if (actype & 0xF0) {
			strcat(str, "I");
			actype >>= 0x06;
		}

		if (actype & BPTYPE_R)
			strcat(str, "R");
		if (actype & BPTYPE_W)
			strcat(str, "W");
		if (actype & BPTYPE_X)
			strcat(str, "X");

		if (bpdat[i].addr_from == bpdat[i].addr_to)
			snprintf(str + strlen(str), 100, " 0x%04hX", bpdat[i].addr_from);
		else
			snprintf(str + strlen(str), 100, " 0x%04hX - 0x%04hX", bpdat[i].addr_from, bpdat[i].addr_to);

		gtk_clist_append(bplist, &inptr);
	}
}


static void editbpx(GtkObject *bpdiag)
{
	word srange, erange;
	GtkCList *bplist;
	gchar *text;
	int row;
	byte i;

	row = (int) gtk_object_get_data(bpdiag, "listpos");

	if (row < 0) return;

	bplist = gtk_object_get_data(bpdiag, "bplist");
	if (gtk_clist_get_text(bplist, row, 0, &text) == GTK_CELL_EMPTY) return;

	if (strchr(text, '-')) {
		sscanf(text, "%*s 0x%04hX - 0x%04hX", &srange, &erange);

	} else {
		sscanf(text, "%*s 0x%04hX", &srange);
		erange = srange;
	}

	i = (strchr(text, 'R')?BPTYPE_R:0x00) | (strchr(text, 'W')?BPTYPE_W:0x00) | (strchr(text, 'X')?BPTYPE_X:0x00);
	if (strchr(text, 'I')) i <<= 0x06;

	gtk_object_set_data(GTK_OBJECT(bpdiag), "presetx", (gpointer) (int) i);
	gtk_object_set_data(GTK_OBJECT(bpdiag), "presets", (gpointer) (int) srange);
	gtk_object_set_data(GTK_OBJECT(bpdiag), "presete", (gpointer) (int) erange);

	create_bpxset(bpdiag);
}


static void delbp(GtkObject *bpdiag)
{
	extern struct wbplist bpdat[maxbp];
	extern byte numbp;

	word srange, erange;
	GtkCList *bplist;
	gchar *text;
	byte i, j;
	int row;

	row = (int) gtk_object_get_data(bpdiag, "listpos");

	if (row < 0) return;

	bplist = gtk_object_get_data(bpdiag, "bplist");
	if (gtk_clist_get_text(bplist, row, 0, &text) == GTK_CELL_EMPTY) return;

	if (strchr(text, '-')) {
		sscanf(text, "%*s 0x%04hX - 0x%04hX", &srange, &erange);

	} else {
		sscanf(text, "%*s 0x%04hX", &srange);
		erange = srange;
	}

	gtk_clist_remove(bplist, row);
	for (i = 0; i < numbp; i++) {
		if ((bpdat[i].addr_from == srange) && (bpdat[i].addr_to == erange)) {
			for (j = i; j < maxbp - 1; j++)
				bpdat[j] = bpdat[j + 1];
			numbp--;
		}
	}
	/* reficons(0); */
}


static void addbpx(GtkObject *bpxset)
{
	extern struct wbplist bpdat[maxbp];
	extern byte numbp;

	byte actype;
	GtkEntry *entry;
	char *endp;
	const char *begp;
	word sxint, exint;
	char ractv, wactv, eactv, range;

	ractv = GTK_TOGGLE_BUTTON(gtk_object_get_data(bpxset, "ractv")) -> active;
	wactv = GTK_TOGGLE_BUTTON(gtk_object_get_data(bpxset, "wactv")) -> active;
	eactv = GTK_TOGGLE_BUTTON(gtk_object_get_data(bpxset, "eactv")) -> active;
	range = GTK_TOGGLE_BUTTON(gtk_object_get_data(bpxset, "range")) -> active;

	entry = gtk_object_get_data(bpxset, "entry");

	if (!(ractv || wactv || eactv)) {
		puts("*** no access type selected ***");
		return;
	}

	if (range) {
		begp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(bpxset, "ssegm")));
		sxint = (word) strtol(begp, &endp, 16);
		if ((*endp != '\0') || (*begp == '\0')) return;
		
		begp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(bpxset, "esegm")));
		exint = (word) strtol(begp, &endp, 16);
		if ((*endp != '\0') || (*begp == '\0')) return;
		if (exint < sxint) return;

	} else {
		begp = gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(bpxset, "xsegm")));
		sxint = (word) strtol(begp, &endp, 16);
		if ((*endp != '\0') || (*begp == '\0')) return;

		exint = sxint + ((*(gtk_entry_get_text(entry)) == 'B')?0:1);
	}

	if ((gtk_object_get_data(GTK_OBJECT(bpxset), "edited")))
		delbp(GTK_OBJECT(gtk_object_get_data(bpxset, "parent")));

	actype = (ractv?BPTYPE_R:0x00) | (wactv?BPTYPE_W:0x00) | (eactv?BPTYPE_X:0x00);
	if (GTK_TOGGLE_BUTTON(gtk_object_get_data(bpxset, "iactv")) -> active)
		actype = (actype & 0x03) << 0x06;

	bpdat[numbp].type = actype;
	bpdat[numbp].addr_from = sxint;
	bpdat[numbp].addr_to = exint;
	numbp++;

	/* reficons(0); */
	ref_bplist(GTK_CLIST(gtk_object_get_data(GTK_OBJECT(gtk_object_get_data(bpxset, "parent")), "bplist")));
	gtk_object_destroy(bpxset);
}


static void tracklist(GtkWidget *widget, gint row, gint col, GdkEventButton *event, GtkObject *bpdiag)
{
	gtk_object_set_data(GTK_OBJECT(bpdiag), "listpos", (gpointer) row);
}


static void create_bpdiag(void)
{
	GtkWidget *bpdiag;
	GtkWidget *bplist, *scroller, *dvert;
	GtkWidget *button1, *button2, *button3, *button4, *brow1, *brow2, *bvsep, *diag_aa;


	bpdiag = gtk_dialog_new();

	bplist = gtk_clist_new(1);
		gtk_clist_set_column_width(GTK_CLIST(bplist), 0, 80);
		gtk_clist_column_titles_hide(GTK_CLIST(bplist));
		gtk_signal_connect(GTK_OBJECT(bplist), "select_row", GTK_SIGNAL_FUNC(tracklist), bpdiag);
		ref_bplist(GTK_CLIST(bplist));

	gtk_widget_show(bplist);

	scroller = gtk_scrolled_window_new(NULL, NULL);
		gtk_container_add(GTK_CONTAINER(scroller), bplist);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	gtk_widget_show(scroller);


	button1 = gtk_button_new_with_label("Add");
		gtk_signal_connect_object(GTK_OBJECT(button1), "clicked", GTK_SIGNAL_FUNC(create_bpxset), GTK_OBJECT(bpdiag));
	gtk_widget_show(button1);

	button2 = gtk_button_new_with_label("Edit");
		gtk_signal_connect_object(GTK_OBJECT(button2), "clicked", GTK_SIGNAL_FUNC(editbpx), GTK_OBJECT(bpdiag));
	gtk_widget_show(button2);

	button3 = gtk_button_new_with_label("Delete");
		gtk_signal_connect_object(GTK_OBJECT(button3), "clicked", GTK_SIGNAL_FUNC(delbp), GTK_OBJECT(bpdiag));
	gtk_widget_show(button3);

	button4 = gtk_button_new_with_label("Dismiss");
		gtk_signal_connect_object(GTK_OBJECT(button4), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(bpdiag));
	gtk_widget_show(button4);

	brow1 = gtk_hbutton_box_new();
		gtk_container_add(GTK_CONTAINER(brow1), button1);
		gtk_container_add(GTK_CONTAINER(brow1), button2);
	gtk_widget_show(brow1);

	brow2 = gtk_hbutton_box_new();
		gtk_container_add(GTK_CONTAINER(brow2), button3);
		gtk_container_add(GTK_CONTAINER(brow2), button4);
	gtk_widget_show(brow2);

	bvsep = gtk_vbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(bvsep), brow1, TRUE, TRUE, 0);
		gtk_box_pack_start(GTK_BOX(bvsep), brow2, TRUE, TRUE, 0);
	gtk_widget_show(bvsep);

	dvert = GTK_DIALOG(bpdiag)->vbox;
		gtk_box_pack_start(GTK_BOX(dvert), scroller, TRUE, TRUE, 0);
	gtk_widget_show(dvert);

	diag_aa = GTK_DIALOG(bpdiag)->action_area;
		gtk_container_set_border_width(GTK_CONTAINER(diag_aa), 10);
		gtk_box_pack_start(GTK_BOX(diag_aa), bvsep, TRUE, FALSE, 0);
	gtk_widget_show(diag_aa);

		gtk_object_set_data(GTK_OBJECT(bpdiag), "listpos", (gpointer) -1);
		gtk_object_set_data(GTK_OBJECT(bpdiag), "bplist", bplist);
		gtk_window_set_modal(GTK_WINDOW(bpdiag), TRUE);
		gtk_window_set_default_size(GTK_WINDOW(bpdiag), -1, 225);
		gtk_window_set_title(GTK_WINDOW(bpdiag), "Set Breakpoints");
		gtk_window_set_position(GTK_WINDOW(bpdiag), GTK_WIN_POS_CENTER);
		gtk_window_set_policy(GTK_WINDOW(bpdiag), TRUE, TRUE, FALSE);
		gtk_signal_connect_object(GTK_OBJECT(bpdiag), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(bpdiag));
	gtk_widget_show(bpdiag);
}


static void create_bpxset(GtkObject *bpdiag)
{
	GtkWidget *bpxset;
	GtkWidget *ndiagbx, *maindlg, *diag_aa;
	GtkWidget *xacframe, *hacbox, *rcheck, *wcheck, *echeck;
	GtkWidget *xadframe, *vadbox, *iocheck;
	GtkWidget *adtbl;
	GtkWidget *single, *access, *access_text, *label1, *saddr;
	GtkWidget *range, *raddrs, *label2 ,*raddre;
	GtkWidget *hbbox, *button1, *button2;
	GSList *bptype_group = NULL;
	GList *access_items = NULL;
	char str[5];
	word actype, acend;

	bpxset = gtk_dialog_new();

	rcheck = gtk_check_button_new_with_label("Read");
	gtk_widget_show(rcheck);

	wcheck = gtk_check_button_new_with_label("Write");
	gtk_widget_show(wcheck);

	echeck = gtk_check_button_new_with_label("Execute");
	gtk_widget_show(echeck);

	hacbox = gtk_hbox_new(TRUE, 0);
		gtk_box_pack_start(GTK_BOX(hacbox), rcheck, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(hacbox), wcheck, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(hacbox), echeck, FALSE, FALSE, 0);
	gtk_widget_show(hacbox);

	xacframe = gtk_frame_new("Type of access");
		gtk_container_set_border_width(GTK_CONTAINER(xacframe), 5);
		gtk_container_add(GTK_CONTAINER(xacframe), hacbox);
	gtk_widget_show(xacframe);



	single = gtk_radio_button_new_with_label(bptype_group, "Single");
		bptype_group = gtk_radio_button_group(GTK_RADIO_BUTTON(single));
	gtk_widget_show(single);

	access = gtk_combo_new();
		access_items = g_list_append(access_items, "Byte");
		access_items = g_list_append(access_items, "Word");
		gtk_combo_set_popdown_strings(GTK_COMBO(access), access_items);
		g_list_free(access_items);
	gtk_widget_show(access);
	access_text = GTK_COMBO(access)->entry;
		gtk_widget_set_usize(access_text, 50, -2);
		gtk_entry_set_editable(GTK_ENTRY(access_text), FALSE);
		gtk_entry_set_text(GTK_ENTRY(access_text), "Byte");
	gtk_widget_show(access_text);

	label1 = gtk_label_new("at");
	gtk_widget_show(label1);

	saddr = gtk_entry_new_with_max_length(4);
		gtk_widget_set_usize(saddr, 50, -2);
	gtk_widget_show(saddr);


	range = gtk_radio_button_new_with_label(bptype_group, "Range");
		bptype_group = gtk_radio_button_group(GTK_RADIO_BUTTON(range));
	gtk_widget_show(range);


	raddrs = gtk_entry_new_with_max_length(4);
		gtk_widget_set_usize(raddrs, 50, -2);
	gtk_widget_show(raddrs);

	label2 = gtk_label_new("to");
	gtk_widget_show(label2);

	raddre = gtk_entry_new_with_max_length(4);
		gtk_widget_set_usize(raddre, 50, -2);
	gtk_widget_show(raddre);

	adtbl = gtk_table_new(2, 4, TRUE);
		gtk_table_attach(GTK_TABLE(adtbl), single, 0, 1, 0, 1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
		gtk_table_attach(GTK_TABLE(adtbl), access, 1, 2, 0, 1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
		gtk_table_attach(GTK_TABLE(adtbl), label1, 2, 3, 0, 1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
		gtk_table_attach(GTK_TABLE(adtbl), saddr, 3, 4, 0, 1, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);

		gtk_table_attach(GTK_TABLE(adtbl), range, 0, 1, 1, 2, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
		gtk_table_attach(GTK_TABLE(adtbl), raddrs, 1, 2, 1, 2, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
		gtk_table_attach(GTK_TABLE(adtbl), label2, 2, 3, 1, 2, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
		gtk_table_attach(GTK_TABLE(adtbl), raddre, 3, 4, 1, 2, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0);
	gtk_widget_show(adtbl);


	iocheck = gtk_check_button_new_with_label("I/O Port Address");
	gtk_widget_show(iocheck);

	vadbox = gtk_vbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(vadbox), iocheck, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(vadbox), adtbl, TRUE, TRUE, 0);
	gtk_widget_show(vadbox);

	xadframe = gtk_frame_new("Address");
		gtk_container_add(GTK_CONTAINER(xadframe), vadbox);
		gtk_container_set_border_width(GTK_CONTAINER(xadframe), 5);
	gtk_widget_show(xadframe);


	maindlg = gtk_vbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(maindlg), xacframe, TRUE, TRUE, 0);
		gtk_box_pack_start(GTK_BOX(maindlg), xadframe, TRUE, TRUE, 0);
	gtk_widget_show(maindlg);

	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(single), TRUE);


	ndiagbx = GTK_DIALOG(bpxset)->vbox;
		gtk_box_pack_start(GTK_BOX(ndiagbx), maindlg, TRUE, TRUE, 0);
	gtk_widget_show(ndiagbx);


	button1 = gtk_button_new_with_label("Ok");
		gtk_signal_connect_object(GTK_OBJECT(button1), "clicked", GTK_SIGNAL_FUNC(addbpx), GTK_OBJECT(bpxset));
	gtk_widget_show(button1);

	button2 = gtk_button_new_with_label("Cancel");
		gtk_signal_connect_object(GTK_OBJECT(button2), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(bpxset));
	gtk_widget_show(button2);

	hbbox = gtk_hbutton_box_new();
		gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_SPREAD);
		gtk_container_add(GTK_CONTAINER(hbbox), button1);
		gtk_container_add(GTK_CONTAINER(hbbox), button2);
	gtk_widget_show(hbbox);


	diag_aa = GTK_DIALOG(bpxset)->action_area;
		gtk_container_set_border_width(GTK_CONTAINER(diag_aa), 10);
		gtk_box_pack_start(GTK_BOX(diag_aa), hbbox, TRUE, TRUE, 0);
	gtk_widget_show(diag_aa);

		gtk_object_set_data(GTK_OBJECT(bpxset), "parent", bpdiag);
		gtk_object_set_data(GTK_OBJECT(bpxset), "ractv", rcheck);
		gtk_object_set_data(GTK_OBJECT(bpxset), "wactv", wcheck);
		gtk_object_set_data(GTK_OBJECT(bpxset), "eactv", echeck);
		gtk_object_set_data(GTK_OBJECT(bpxset), "iactv", iocheck);
		gtk_object_set_data(GTK_OBJECT(bpxset), "range", range);
		gtk_object_set_data(GTK_OBJECT(bpxset), "entry", access_text);
		gtk_object_set_data(GTK_OBJECT(bpxset), "ssegm", raddrs);
		gtk_object_set_data(GTK_OBJECT(bpxset), "esegm", raddre);
		gtk_object_set_data(GTK_OBJECT(bpxset), "xsegm", saddr);


		if ((actype = (word) (int) gtk_object_get_data(bpdiag, "presetx"))) {
			gtk_object_remove_data(bpdiag, "presetx");
			gtk_object_set_data(GTK_OBJECT(bpxset), "edited", (gpointer) 0x0001);

			if (actype & 0xF0) {
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(iocheck), TRUE);
				actype >>= 0x06;
			}

			if (actype & BPTYPE_R)
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rcheck), TRUE);
			if (actype & BPTYPE_W)
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wcheck), TRUE);
			if (actype & BPTYPE_X)
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(echeck), TRUE);

			actype = (word) (int) gtk_object_get_data(GTK_OBJECT(bpdiag), "presets");
			acend = (word) (int) gtk_object_get_data(GTK_OBJECT(bpdiag), "presete");
			snprintf(str, 5, "%04hX", actype);

			if (acend <= actype + 1) {
				if (acend - actype) gtk_entry_set_text(GTK_ENTRY(access_text), "Word");
				gtk_entry_set_text(GTK_ENTRY(saddr), str);

			} else {
				gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(range), TRUE);
				gtk_entry_set_text(GTK_ENTRY(raddrs), str);
				snprintf(str, 5, "%04hX", acend);
				gtk_entry_set_text(GTK_ENTRY(raddre), str);
			}
		}

		gtk_window_set_modal(GTK_WINDOW(bpxset), TRUE);
		gtk_window_set_default_size(GTK_WINDOW(bpxset), -1, 230);
		gtk_window_set_title(GTK_WINDOW(bpxset), "Set Breakpoint");
		gtk_window_set_position(GTK_WINDOW(bpxset), GTK_WIN_POS_CENTER);
		gtk_signal_connect_object(GTK_OBJECT(bpxset), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(bpxset));
	gtk_widget_show(bpxset);
}
	/* Breakpoints <<< */


	/* >>> hexbox */
static void refreshhex(GtkWidget *hexcode, word hexloc)
{
	char str[10][9], *co[10];
	byte i, k;
	word j;

	if (hexloc != 0xFFFF)
		gtk_object_set_user_data(GTK_OBJECT(hexcode), (gpointer) (int) hexloc);
	else
		hexloc = (word) (int) gtk_object_get_user_data(GTK_OBJECT(hexcode));

	gtk_clist_freeze(GTK_CLIST(hexcode));
	gtk_clist_clear(GTK_CLIST(hexcode));

	for (i = 0; i < 10; i++)
		co[i] = str[i];
	str[9][8] = '\0';

	for (j = 0; j < 8192; j++) { /***********5**/
		sprintf(str[0], "%04X", (hexloc + 0x08 * j)&0xffff);
		for (i = 1; i < 9; i++) {
			k = Z80_RDMEM(hexloc + i - 1 + 0x08 * j);
			sprintf(str[i], "%02X", k);

			if ((k >= 0x20) && (k < 0x7E))
				str[9][i - 1] = k;
			else
				str[9][i - 1] = '.';

		}
	
		gtk_clist_append(GTK_CLIST(hexcode), co);
		
		/*if (gtk_clist_row_is_visible(GTK_CLIST(hexcode),j)
		    != GTK_VISIBILITY_FULL)
		    break;*/
	}
	gtk_clist_thaw(GTK_CLIST(hexcode));
}


static void clhex(unsigned short x, unsigned short i, struct debuginfo *debugdat)
{
	if (x > 0xFFD8) x = 0xFFD8;
	refreshhex(debugdat->hexcode, x);
}


static void cchex(unsigned short x, unsigned short i, struct debuginfo *debugdat)
{
	Z80_WRMEM(i, (byte) x);
	refreshhex(debugdat->hexcode, 0xFFFF);
	refreshstk(debugdat->stkcode);
}


static void hexchange(GtkWidget *widget, gint row, gint col, GdkEventButton *event, gpointer data)
{
	unsigned short z, hexloc;
	char label[15], datum[5];
	char *text, *endp;

	data = gtk_object_get_user_data(GTK_OBJECT(data));

	gtk_clist_unselect_row(GTK_CLIST(widget), row, col);
	gtk_clist_get_text(GTK_CLIST(widget), row, 0, &text);

	hexloc = (unsigned short) strtol(text, &endp, 16);
	g_assert((!(*endp)) && (*text));

	z = hexloc + col - 1;
	if ((col > 0) && (col < 9) && (z >= 0x8000)) {
		sprintf(label, "Byte at 0x%04X", z);
		sprintf(datum, "%02X", Z80_RDMEM(z));

		create_hexbox("Change Memory", label, datum, 2, (ptrfunc) cchex, z, data);
	} else if (!col) {
		sprintf(datum, "%04X", hexloc);
		create_hexbox("Code Panel", "Goto", datum, 4, (ptrfunc) clhex, 0, data);
	}
}
	/* hexbox <<< */


static gint debugend(GtkWidget *widget, gpointer debugw, gpointer data)
{
	G_LOCK_EXTERN(halted);
	extern int halted;
	extern word Z80_Trace;

	if ((debugw) && ((int) data != 0xBADC0DE))
		widget = GTK_WIDGET(debugw);

	Z80_Trace = 0;

	gtk_widget_hide(widget);

	G_LOCK(halted);
	halted = 0;
	G_UNLOCK(halted);

	return(TRUE);
}


static gint shutdown(GtkObject *debugw)
{
	struct debuginfo *debugdat;
	
	debugdat = gtk_object_get_user_data(debugw);
	free(debugdat);
	return(FALSE);
}


static void dostep(void)
{
	G_LOCK_EXTERN(halted);
	extern int halted;

	trace_pos = 0;

	G_LOCK(halted);
	halted = 0;
	G_UNLOCK(halted);
}


static void reficons(byte sel, struct debuginfo *debugdat)
{
	extern struct wbplist bpdat[maxbp];
	extern Z80_Regs R;
	extern byte numbp;

	byte i, j;
	byte b[5];
	char st[40];
	unsigned char taken;
	unsigned short lstlp = 0xFFFF;
	GdkPixmap *pix1, *pix2, *pix3, *pixc;
	GdkBitmap *msk1, *msk2, *msk3, *mskc;

	pix1 = NULL;
	create_pixmap("bpx.xpm", GTK_WIDGET(debugdat->dasm), &pix2, &msk2);
	create_pixmap("clear.xpm", GTK_WIDGET(debugdat->dasm), &pixc, &mskc);

	for (j = listlen - 1; j < listlen; j--) {
		gtk_clist_set_pixmap(GTK_CLIST(debugdat->dasm), j, 0, pixc, mskc);
		if (lstpc[j] == lstlp) continue;
		lstlp = lstpc[j];

		if (lstpc[j] == R.PC.D) {
			for (i = 0; i < 5; i++)
				b[i] = Z80_RDMEM(R.PC.D + i);

			dasm(b, st, R.PC.D, &taken);

			switch (taken) {
				case 0x88:
					create_pixmap("pc.xpm", GTK_WIDGET(debugdat->dasm), &pix1, &msk1);
					create_pixmap("pcbpx.xpm", GTK_WIDGET(debugdat->dasm), &pix3, &msk3);
					break;

				case 0x00:
					create_pixmap("pc_ignored.xpm", GTK_WIDGET(debugdat->dasm), &pix1, &msk1);
					create_pixmap("pcx_i.xpm", GTK_WIDGET(debugdat->dasm), &pix3, &msk3);
					break;

				default:
					create_pixmap("pc_taken.xpm", GTK_WIDGET(debugdat->dasm), &pix1, &msk1);
					create_pixmap("pcx_t.xpm", GTK_WIDGET(debugdat->dasm), &pix3, &msk3);
					break;
			}
			gtk_clist_set_pixmap(GTK_CLIST(debugdat->dasm), j, 0, pix1, msk1);
			if (sel)
				gtk_clist_select_row(GTK_CLIST(debugdat->dasm), j, 0);
		}

		for (i = 0; i < numbp; i++) {
			if ((lstpc[j] == bpdat[i].addr_to) && (lstpc[j] == bpdat[i].addr_from) && (bpdat[i].type & BPTYPE_X)) {
				if (lstpc[j] == R.PC.D)
					gtk_clist_set_pixmap(GTK_CLIST(debugdat->dasm), j, 0, pix3, msk3);
				else
					gtk_clist_set_pixmap(GTK_CLIST(debugdat->dasm), j, 0, pix2, msk2);
			}
		}
	}

	if (pix1) {
		gdk_pixmap_unref(pix1);	gdk_bitmap_unref(msk1); 
		gdk_pixmap_unref(pix3); gdk_bitmap_unref(msk3);
	}
	gdk_pixmap_unref(pix2); gdk_pixmap_unref(pixc);
	gdk_bitmap_unref(msk2); gdk_bitmap_unref(mskc);
}


static void refreshstk(GtkWidget *stkcode)
{
	char str[2][6], *co[2];
	unsigned short i;

	gtk_clist_freeze(GTK_CLIST(stkcode));
	gtk_clist_clear(GTK_CLIST(stkcode));

	co[0] = str[0];
	co[1] = str[1];
	i = getreg(10) + 1;
	while  (i > 0x0010) {
		sprintf(str[0], "%04X:", i - 1);
		sprintf(str[1], "%04X", Z80_RDMEM(i - 1) + (Z80_RDMEM(i) << 0x08));

		gtk_clist_append(GTK_CLIST(stkcode), co);
		i += 0x0002;
	}

	gtk_clist_thaw(GTK_CLIST(stkcode));
}


static void refreshdebugger(unsigned short xpc, struct debuginfo *debugdat)
{
	GdkColor mycolor;

	short spc;
	byte i, j, b[5];
	char *str[3], st[50], addr[5];
	unsigned short lstlbl = 0xFFFF;

	static unsigned short oldstack = 0xFFFF;

	if ((writestk) || (oldstack != getreg(10)))
		refreshstk(debugdat->stkcode);

	oldstack = getreg(10);
	writestk = 0;
/* INC SP instructions... */


	/* printf("Refreshing debugger at %04X\n", xpc); */


	for (j = 0; j < listlen &&
		     gtk_clist_row_is_visible(GTK_CLIST(debugdat->dasm), j)
		     == GTK_VISIBILITY_FULL; j++) {
		if (lstpc[j] == xpc) {
			/* printf("selecting row: %d\n",j); */
			gtk_clist_select_row(GTK_CLIST(debugdat->dasm),j, 0);
			xpc = lstpc[0];
		}
	}


/* Has the advantage of preventing the list from flickering,
 * but then we miss out all dynamically changed code... */
	if (lstpc[0] != xpc) {
		/* printf("refreshing\n"); */
		gtk_clist_freeze(GTK_CLIST(debugdat->dasm));
		gtk_clist_clear(GTK_CLIST(debugdat->dasm));
		for (j = 0; j < listlen; j++) {
			lstpc[j] = xpc;

			for (i = 0; i < 5; i++)
				b[i] = Z80_RDMEM(xpc + i);

			snprintf(addr, 5, "%04X", xpc);	

			str[0] = NULL;
			str[1] = addr;
			str[2] = st;
			spc = dasm(b, st, xpc, NULL);

			if ((lstlbl != xpc) && (translate(xpc, &str[2]))) {
				gtk_clist_append(GTK_CLIST(debugdat->dasm), str);

				gdk_color_white(gdk_colormap_get_system(), &mycolor);
				gtk_clist_set_background(GTK_CLIST(debugdat->dasm), j, &mycolor);

				gdk_color_black(gdk_colormap_get_system(), &mycolor);
				gtk_clist_set_foreground(GTK_CLIST(debugdat->dasm), j, &mycolor);

				lstlbl = xpc;
				continue;
			}
			lstlbl = 0xFFFF;

			gtk_clist_append(GTK_CLIST(debugdat->dasm), str);
			xpc += spc;

			if (gtk_clist_row_is_visible(GTK_CLIST(debugdat->dasm),
						     j) != GTK_VISIBILITY_FULL)
				break;
		}

		if (gtk_clist_row_is_visible(GTK_CLIST(debugdat->dasm), j)
		    != GTK_VISIBILITY_FULL)
		    gtk_clist_remove(GTK_CLIST(debugdat->dasm),j);

		gtk_clist_select_row(GTK_CLIST(debugdat->dasm), 0, 0);

		gtk_clist_thaw(GTK_CLIST(debugdat->dasm));
	}

	reficons(0, debugdat);

	for (i = 0; i < 12; i++) {
		snprintf(st, 10, "%s: %04X", rlabels[i], getreg(i));
		gtk_label_set_text(GTK_LABEL(debugdat->regl[i]), st);
	}

/* Has No Effect Whatsoever
 * gtk_label_set_justify(debugdat->regl[i], GTK_JUSTIFY_LEFT); */
}


	/* >>> Symbols */
static void clearsyms(GtkWidget *widget)
{
	word i;
	struct debuginfo *debugdat;

	debugdat = (struct debuginfo *) gtk_object_get_user_data(GTK_OBJECT(widget));

	i = lstpc[0];
	clearsymbols();
	refreshdebugger(i, debugdat);
}


static void _loadsym(GtkWidget *filewin)
{
	struct debuginfo *debugdat;
	word i;

	debugdat = (struct debuginfo *) gtk_object_get_user_data(GTK_OBJECT(gtk_object_get_user_data(filewin)));

	i = lstpc[0];
	loadsyms(getfilename(filewin));
	gtk_widget_destroy(GTK_WIDGET(filewin));

	refreshdebugger(i, debugdat);
}


static void loadsym(GtkWidget *widget)
{
	GtkWidget *filew;

	filew = create_filedlg("Load symbols", 0, gtk_widget_destroy, _loadsym);
	gtk_object_set_user_data(GTK_OBJECT(filew), (gpointer) widget);
	setfilename(filew);
	gtk_widget_show(filew);
}	/* Symbols <<< */


static void gotopc(GtkObject *debugw)
{
	extern Z80_Regs R;
	struct debuginfo *debugdat;

	trace_pos = 0;

	debugdat = gtk_object_get_user_data(debugw);

	refreshdebugger(R.PC.D, debugdat);
}


	/* >>> SetPC */
static void ccasm(unsigned short x, unsigned short i,
		  struct debuginfo *debugdat)
{
	refreshdebugger(x, debugdat);
}


static void setpc(GtkObject *debugw)
{
	extern Z80_Regs R;

	struct debuginfo *debugdat;
	char data[5];

	debugdat = gtk_object_get_user_data(debugw);
	snprintf(data, 5, "%04X", R.PC.D);
	create_hexbox("Disassembly", "Goto", data, 4, (ptrfunc) ccasm,
		      0, debugdat);
}
	/* SetPC <<< */


static void stepovr(GtkWidget *widget, GtkObject *debugw)
{
	extern opcode_fn opcode_main[256];
	extern unsigned short stepbpx;
	/* extern struct hardware *hw; */
	extern Z80_Regs R;

	struct debuginfo *debugdat;
	unsigned short xpc;
	unsigned opcode;
	byte i, b[5];
	char st[20];
	gint retval;

	trace_pos = 0;

	if (!(debugw))
		debugw = GTK_OBJECT(widget);

	debugdat = gtk_object_get_user_data(debugw);

	xpc = R.PC.D;
	for (i = 0; i < 5; i++)
		b[i] = Z80_RDMEM(xpc + i);

	stepbpx = xpc + dasm(b, st, xpc, NULL);

	while (R.PC.D == xpc) {
		opcode = Z80_RDMEM(R.PC.D);
		R.PC.D++;
		(*(opcode_main[opcode]))();
	}

	if (R.PC.D == stepbpx) {
		stepbpx = 0;
		refreshdebugger(R.PC.D, debugdat);
	} else
		gtk_signal_emit_by_name(debugw, "delete_event", NULL, &retval);
}

static void tracebk(GtkWidget *widget, GtkObject *debugw)
{
	struct debuginfo *debugdat;

	extern unsigned int pc_trace[];
	extern unsigned int pc_count;

	if (!(debugw))
		debugw = GTK_OBJECT(widget);

	debugdat = gtk_object_get_user_data(debugw);

	if (trace_pos<256)
		trace_pos++;

	refreshdebugger(pc_trace[(pc_count-trace_pos-1)%256], debugdat);
}

static void tracefwd(GtkWidget *widget, GtkObject *debugw)
{
	struct debuginfo *debugdat;

	extern unsigned int pc_trace[];
	extern unsigned int pc_count;

	if (!(debugw))
		debugw = GTK_OBJECT(widget);

	debugdat = gtk_object_get_user_data(debugw);

	if (trace_pos>0)
		trace_pos--;

	refreshdebugger(pc_trace[(pc_count-trace_pos-1)%256],debugdat);
}


	/* >>> Change reg */
static void ccreg(unsigned short x, unsigned short i, gpointer debugdat)
{
	extern Z80_Regs R;

	setreg(i, x);
	refreshdebugger(R.PC.D, (struct debuginfo *) debugdat);
}


static gint chreg(GtkWidget *widget, GdkEventKey *event, gpointer rselected)
{
	struct debuginfo *debugdat;
	char label[15], data[5];

	debugdat = gtk_object_get_user_data(GTK_OBJECT(widget));
	snprintf(label, 15, "Value for %s:", rlabels[(int) rselected]);
	snprintf(data, 5, "%04X", getreg((int) rselected));

	create_hexbox("Change Register", label, data, 4, (ptrfunc) ccreg,
		      (int) rselected, (gpointer) debugdat);

	return(TRUE);
}
	/* Change reg <<< */

static gboolean debug_idle(gpointer debugw)
{
	extern Z80_Regs R;

	struct debuginfo *debugdat;

	G_LOCK(traps);

	if (trap_want_db) {
		gtk_widget_show(debugw);
		debugdat = gtk_object_get_user_data(GTK_OBJECT(debugw));
		trace_pos = 0;
		refreshdebugger(R.PC.D, debugdat);
		trap_want_db = 0;
	}
	if (trap_want_save) {
		trap_save();
		trap_want_save = 0;
	}

	G_UNLOCK(traps);

	return TRUE;
}


static gint setup(GtkObject *debugw)
{
	extern unsigned short stepbpx;
	byte i;

	stepbpx = 0;
	for (i = 0; i < listlen; i++)
		lstpc[i] = 0xFFFF;

	return(FALSE);
}


static void setpctoselection(GtkObject *debugw)
{
	extern Z80_Regs R;

	char st[20];
	gchar *text, *endp;
	struct debuginfo *debugdat;

	debugdat = gtk_object_get_user_data(debugw);
	gtk_clist_get_text(GTK_CLIST(debugdat->dasm), debugdat->disass_row,
			   1, &text);
	R.PC.D = (unsigned short) strtol(text, &endp, 16);
	if ((*endp != '\0') || (*text == '\0')) return;

	reficons(1, debugdat);
	snprintf(st, 10, "%s: %04X", rlabels[4], getreg(4));
	gtk_label_set_text(GTK_LABEL(debugdat->regl[4]), st);
}


static void selectline(GtkObject *widget, gint row, gint col,
		       GdkEventButton *event, gpointer data)
{
	struct debuginfo *debugdat;

	/* printf("changed row to %d\n", row); */

/* CLIST Doesn't provide a getrow function! */
	debugdat = gtk_object_get_user_data(widget);
	debugdat->disass_row = row;
}


static int chkdbgwin(GtkObject *debugw, GdkEventKey *event, gpointer user_data)
{
	unsigned short svpc;
	struct debuginfo *debugdat;
	/* gint retval; */

	debugdat = gtk_object_get_user_data(debugw);

	switch (event->keyval) {
/*		case GDK_F2:
			setbpx(NULL, NULL, NULL);
			break;
*/
		case GDK_Down:
			if (debugdat->disass_row == listlen - 1 ||
			    gtk_clist_row_is_visible(GTK_CLIST(debugdat->dasm),
						     debugdat->disass_row+1)
			    !=GTK_VISIBILITY_FULL) {
				svpc = lstpc[debugdat->disass_row];
				lstpc[debugdat->disass_row] = 0x0000;
				lstpc[debugdat->disass_row - 1] = 0x0000;
				refreshdebugger(svpc, debugdat);
				debugdat->disass_row = 0;
			}
			gtk_clist_select_row(GTK_CLIST(debugdat->dasm),
					     debugdat->disass_row + 1, 0);
			break;

		case GDK_Up:
			if (!debugdat->disass_row) {
				refreshdebugger(lstpc[0] - 1, debugdat);
				debugdat->disass_row = 1;
			}
			gtk_clist_select_row(GTK_CLIST(debugdat->dasm),
					     debugdat->disass_row - 1, 0);
			break;
	}
	return(FALSE);
}

static void resize(GtkWidget *widget, GtkRequisition *req, gpointer data)
{
	unsigned short initpc, pc;
	struct debuginfo *debugdat;
	debugdat = gtk_object_get_user_data(GTK_OBJECT(data));

	initpc = lstpc[0];
	lstpc[0] = 0;

	refreshdebugger(initpc, debugdat);

	pc = lstpc[debugdat->disass_row];
	lstpc[debugdat->disass_row] = 0;

	refreshdebugger(pc, debugdat);
}

/* Static <<< */


void create_debugger()
{

	GtkWidget *trio, *duo, *paned, *regbox, *toolbar, *xframe, *hexcode,
		*regev, *dasmlist, *stkframe, *bduo, *stkcode, *stkscroll,
		*dasmscroll, *hexscroll/*, *statbar*/;

	struct debuginfo *debugdat;
	GtkWidget *debugwin;
/*	gint scontext;*/
	byte i;
	
	GdkPixmap *pixmap;
	GdkBitmap *mask;
	GtkWidget *icon;

	debugdat = malloc(sizeof(struct debuginfo));

	debugwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
		gtk_window_set_modal(GTK_WINDOW(debugwin), TRUE);
		gtk_widget_set_usize(debugwin, 440, 300);
/*	       gtk_window_set_policy(GTK_WINDOW(debugwin), FALSE, FALSE, TRUE);
 *	unfortunatly, also changes window's border... */
		gtk_window_set_title(GTK_WINDOW(debugwin), "Tilem Debugger");

	dasmlist = gtk_clist_new(3);
		gtk_widget_set_name(dasmlist, "monow");

		gtk_clist_set_column_width(GTK_CLIST(dasmlist), 0, 15);
		gtk_clist_set_column_width(GTK_CLIST(dasmlist), 1, 50);
		gtk_clist_set_column_width(GTK_CLIST(dasmlist), 2, 120);
		gtk_clist_column_titles_hide(GTK_CLIST(dasmlist));
/*		gtk_widget_set_sensitive(dasmlist, FALSE);*/
		GTK_WIDGET_UNSET_FLAGS(dasmlist, GTK_CAN_FOCUS);
	gtk_widget_show(dasmlist);

	dasmscroll = gtk_scrolled_window_new(NULL, NULL);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dasmscroll),
					       GTK_POLICY_NEVER,
					       GTK_POLICY_AUTOMATIC);
		gtk_container_add(GTK_CONTAINER(dasmscroll), dasmlist);
	gtk_widget_show(dasmscroll);

	regbox = gtk_table_new(6, 2, TRUE);
		for (i = 0; i < 12; i++) {
			regev = gtk_event_box_new();
				debugdat->regl[i] = gtk_label_new("----");
					gtk_container_add(GTK_CONTAINER(regev),
							  debugdat->regl[i]);
				gtk_widget_set_name(debugdat->regl[i],"monow");
				gtk_widget_show(debugdat->regl[i]);

/* ? IX couldn't be changed on purpose */
				gtk_widget_set_events(regev,
						      GDK_BUTTON_PRESS_MASK);
				gtk_object_set_user_data(GTK_OBJECT(regev),
							 (gpointer) debugdat);
				gtk_signal_connect(GTK_OBJECT(regev),
						   "button_press_event",
						   GTK_SIGNAL_FUNC(chreg),
						   (gpointer) (int) i);
			gtk_widget_show(regev);

			gtk_table_attach(GTK_TABLE(regbox), regev,
					 i / 6, i / 6 + 1,
					 i % 6, i % 6 + 1,
					 0, 0, 3, 0);
		}
	gtk_widget_show(regbox);

	xframe = gtk_frame_new("Registers");
		gtk_container_set_border_width(GTK_CONTAINER(xframe), 5);
		gtk_container_add(GTK_CONTAINER(xframe), regbox);
	gtk_widget_show(xframe);

/*	hexduo = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjust));
	gtk_widget_show(hexduo);
*/
	duo = gtk_hbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(duo), dasmscroll, TRUE, TRUE, 0);
		gtk_box_pack_start(GTK_BOX(duo), xframe, FALSE, FALSE, 0);
		/* gtk_box_pack_end(GTK_BOX(duo), hexduo, FALSE, FALSE, 0); */
	gtk_widget_show(duo);


#ifdef USE_GTK_1_2
	toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
				  GTK_TOOLBAR_ICONS);
	gtk_toolbar_set_button_relief(GTK_TOOLBAR(toolbar), GTK_RELIEF_NONE);
#else
	toolbar = gtk_toolbar_new();
#endif


		create_pixmap("run.xpm", toolbar, &pixmap, &mask);
		icon = gtk_pixmap_new(pixmap, mask);
		gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL, "Run",
					"Private", icon,
					GTK_SIGNAL_FUNC(debugend), debugwin);

		gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));

		create_pixmap("step.xpm", toolbar, &pixmap, &mask);
		icon = gtk_pixmap_new(pixmap, mask);
		gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL, "Step",
					"Private", icon,
					GTK_SIGNAL_FUNC(dostep), NULL);

		create_pixmap("stepovr.xpm", toolbar, &pixmap, &mask);
		icon = gtk_pixmap_new(pixmap, mask);
		gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL,
					"Step Over", "Private", icon,
					GTK_SIGNAL_FUNC(stepovr),
					GTK_OBJECT(debugwin));

		gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));

		create_pixmap("setbpx.xpm", toolbar, &pixmap, &mask);
		icon = gtk_pixmap_new(pixmap, mask);
		gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL,
					"Toggle Breakpoint", "Private", icon,
					GTK_SIGNAL_FUNC(setbpx),
					GTK_OBJECT(debugwin));

		gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));

		create_pixmap("tracebk.xpm", toolbar, &pixmap, &mask);
		icon = gtk_pixmap_new(pixmap, mask);
		gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL,
					"Trace Backward", "Private", icon,
					GTK_SIGNAL_FUNC(tracebk),
					GTK_OBJECT(debugwin));

		create_pixmap("tracefwd.xpm", toolbar, &pixmap, &mask);
		icon = gtk_pixmap_new(pixmap, mask);
		gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL,
					"Trace Forward", "Private", icon,
					GTK_SIGNAL_FUNC(tracefwd),
					GTK_OBJECT(debugwin));
	gtk_widget_show(toolbar);

	hexcode = gtk_clist_new(10);
		gtk_widget_set_name(hexcode, "monow");

		gtk_clist_set_column_width(GTK_CLIST(hexcode), 0, 40);
		for (i = 1; i < 10; i++)
			gtk_clist_set_column_width(GTK_CLIST(hexcode), i, 16);

		gtk_clist_column_titles_hide(GTK_CLIST(hexcode));
		GTK_WIDGET_UNSET_FLAGS(hexcode, GTK_CAN_FOCUS);
	gtk_widget_show(hexcode);

	hexscroll = gtk_scrolled_window_new(NULL, NULL);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hexscroll),
					       GTK_POLICY_NEVER,
					       GTK_POLICY_ALWAYS);
		gtk_container_add(GTK_CONTAINER(hexscroll),hexcode);
	gtk_widget_show(hexscroll);

	xframe = gtk_frame_new("Memory");
		gtk_container_set_border_width(GTK_CONTAINER(xframe), 5);
		gtk_container_add(GTK_CONTAINER(xframe), hexscroll);
	gtk_widget_show(xframe);


	stkcode = gtk_clist_new(2);
		gtk_widget_set_name(stkcode, "monow");
		gtk_clist_column_titles_hide(GTK_CLIST(stkcode));
		GTK_WIDGET_UNSET_FLAGS(stkcode, GTK_CAN_FOCUS);
		gtk_clist_set_column_width(GTK_CLIST(stkcode), 0, 32);
		gtk_clist_set_column_width(GTK_CLIST(stkcode), 1, 32);
	gtk_widget_show(stkcode);


	stkscroll = gtk_scrolled_window_new(NULL, NULL);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(stkscroll),
					       GTK_POLICY_NEVER,
					       GTK_POLICY_ALWAYS);
		gtk_container_add(GTK_CONTAINER(stkscroll), stkcode);
	gtk_widget_show(stkscroll);


	stkframe = gtk_frame_new("Stack");
		gtk_container_set_border_width(GTK_CONTAINER(stkframe), 5);
		gtk_container_add(GTK_CONTAINER(stkframe), stkscroll);
	gtk_widget_show(stkframe);

	bduo = gtk_hbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(bduo), xframe, TRUE, TRUE, 0);
		gtk_box_pack_start(GTK_BOX(bduo), stkframe, FALSE, FALSE, 0);
	gtk_widget_show(bduo);

/*	statbar = gtk_statusbar_new();
		scontext = gtk_statusbar_get_context_id(GTK_STATUSBAR(statbar), "stdcontext");
		gtk_object_set_data(GTK_OBJECT(debugwin), "statbar", statbar);
		gtk_object_set_data(GTK_OBJECT(statbar), "scontext", (gpointer) scontext);
		gtk_statusbar_push(GTK_STATUSBAR(statbar), scontext, statmess);
	gtk_widget_show(statbar);*/

	paned = gtk_vpaned_new();
		gtk_paned_pack1(GTK_PANED(paned), duo, TRUE, FALSE);
		gtk_paned_pack2(GTK_PANED(paned), bduo, TRUE, FALSE);

	gtk_widget_show(paned);

	trio = gtk_vbox_new(FALSE, 0);
		gtk_box_pack_start(GTK_BOX(trio), toolbar, FALSE, FALSE, 0);
		gtk_box_pack_start(GTK_BOX(trio), paned, TRUE, TRUE, 0);
		/*gtk_box_pack_start(GTK_BOX(trio), duo, TRUE, TRUE, 0);
		  gtk_box_pack_start(GTK_BOX(trio), bduo, TRUE, TRUE, 0);*/
		/* gtk_box_pack_start(GTK_BOX(trio), statbar, TRUE, TRUE, 0); */
	gtk_widget_show(trio);

		gtk_container_add(GTK_CONTAINER(debugwin), trio);

		create_menus_widget(debugwin, debugwin, codemenu, sizeof(codemenu) / sizeof(GtkItemFactoryEntry), "<debug>");
		create_menus_widget(dasmlist, debugwin, codemenu, sizeof(codemenu) / sizeof(GtkItemFactoryEntry), "<debug>");

		gtk_signal_connect(GTK_OBJECT(debugwin), "key_press_event", GTK_SIGNAL_FUNC(chkdbgwin), NULL);
		gtk_signal_connect(GTK_OBJECT(hexcode), "select_row", GTK_SIGNAL_FUNC(hexchange), debugwin);
		gtk_signal_connect_object(GTK_OBJECT(dasmlist), "select_row", GTK_SIGNAL_FUNC(selectline), GTK_OBJECT(debugwin));
		gtk_signal_connect(GTK_OBJECT(debugwin), "delete_event", GTK_SIGNAL_FUNC(debugend), (gpointer) 0xBADC0DE);
		gtk_signal_connect(GTK_OBJECT(debugwin), "destroy", GTK_SIGNAL_FUNC(shutdown), NULL);
		gtk_signal_connect(GTK_OBJECT(debugwin), "show", GTK_SIGNAL_FUNC(setup), NULL);
		gtk_signal_connect(GTK_OBJECT(dasmlist), "size_allocate", GTK_SIGNAL_FUNC(resize), GTK_OBJECT(debugwin));

		gtk_object_set_user_data(GTK_OBJECT(debugwin), (gpointer) debugdat);
		gtk_object_set_user_data(GTK_OBJECT(dasmlist), (gpointer) debugdat);

	debugdat->hexcode = hexcode;
	debugdat->stkcode = stkcode;
	debugdat->dasm = dasmlist;

	/* trap_debug((int) debugwin); */
	/* signal(SIGUSR1, trap_debug); */
	g_idle_add(debug_idle, debugwin);

	trace_pos = 0;

	refreshhex(hexcode, 0x0000);
}



/* >>> Concat */
/* >>> Private */
struct chbxmem {
	unsigned short i;
	GtkWidget *ent;
	gpointer edata;
	ptrfunc func;
	int maxlen;
};
/* Private <<< */


/* >>> Static */
static unsigned short getreg(byte i)
{
	extern Z80_Regs R;

	switch (i) {
		case 0:
			return(R.AF.D);
		case 1:
			return(R.HL.D);
		case 2:
			return(R.DE.D);
		case 3:
			return(R.BC.D);
		case 4:
			return(R.PC.D);
		case 5:
			return(R.IY.D);
		case 6:
			return(R.AF2.D);
		case 7:
			return(R.HL2.D);
		case 8:
			return(R.DE2.D);
		case 9:
			return(R.BC2.D);
		case 10:
			return(R.SP.D);
		case 11:
			return(R.IX.D);
	}

	return(0x0000);
}


static void setreg(byte i, unsigned short v)
{
	extern Z80_Regs R;

	switch (i) {
		case 0:
			R.AF.D = v;
			break;
		case 1:
			R.HL.D = v;
			break;
		case 2:
			R.DE.D = v;
			break;
		case 3:
			R.BC.D = v;
			break;
		case 4:
			R.PC.D = v;
			break;
		case 5:
			R.IY.D = v;
			break;
		case 6:
			R.AF2.D = v;
			break;
		case 7:
			R.HL2.D = v;
			break;
		case 8:
			R.DE2.D = v;
			break;
		case 9:
			R.BC2.D = v;
			break;
		case 10:
			R.SP.D = v;
			break;
		case 11:
			R.IX.D = v;
			break;
	}
}


static void interfunc(GtkObject *dialog)
{
	extern struct symboldat *symbols;
	extern word numsymbols;

	static struct chbxmem *hexdat;
	char *endp;
	const char *begp;
	unsigned short x;
	long int max;
	int i;
	struct symboldat *sym=NULL;

	hexdat = gtk_object_get_user_data(dialog);
	begp = gtk_entry_get_text(GTK_ENTRY(hexdat->ent));
	
	x = (unsigned short) strtol(begp, &endp, 16);
	max = 1L<<(4*(hexdat->maxlen));

	if ((*endp == '\0') && (*begp != '\0') && x < max) {
		(hexdat->func)(x, hexdat->i, hexdat->edata);
	}
	else {
		for (i=0;i<numsymbols;i++) {
			if (0==strcasecmp(symbols[i].label, begp)) {
				sym = &symbols[i];
				i = numsymbols;
			}
		}
		if (sym && sym->address < max) {
			(hexdat->func)(sym->address, hexdat->i, hexdat->edata);
		}
	}

	free(hexdat);
	gtk_widget_destroy(GTK_WIDGET(dialog));
}


static void create_hexbox(char *title, char *label, char *value, char maxlen,
			  ptrfunc func, unsigned short data, gpointer data2)
{
	GtkWidget *dlg, *dlgstf1, *frame, *lblbx, *entry, *dialog_aa, *bbox,
	  *button1, *button2;
	static struct chbxmem *hexdat;

	hexdat = malloc(sizeof(struct chbxmem));

	dlg = gtk_dialog_new();
		gtk_window_set_title(GTK_WINDOW(dlg), title);
		gtk_window_set_modal(GTK_WINDOW(dlg), TRUE);

	button1 = gtk_button_new_with_label("OK");
	gtk_widget_show(button1);

	button2 = gtk_button_new_with_label("Cancel");
	gtk_widget_show(button2);

	bbox = gtk_hbutton_box_new();
		gtk_box_pack_start(GTK_BOX(bbox), button1, FALSE, FALSE, 0);
		gtk_box_pack_end(GTK_BOX(bbox), button2, FALSE, FALSE, 0);
	gtk_widget_show(bbox);

	dialog_aa = GTK_DIALOG(dlg)->action_area;
		gtk_container_set_border_width(GTK_CONTAINER (dialog_aa), 10);
		gtk_box_pack_start(GTK_BOX(dialog_aa), bbox, FALSE, TRUE, 0);
	gtk_widget_show(dialog_aa);

	entry = gtk_entry_new();/*_with_max_length(maxlen);*/
		gtk_entry_set_text(GTK_ENTRY(entry), value);
		gtk_entry_select_region(GTK_ENTRY(entry), 0, maxlen);
	gtk_widget_show(entry);

	lblbx = gtk_hbox_new(FALSE, 0);
		gtk_container_set_border_width(GTK_CONTAINER(lblbx), 5);
		gtk_box_pack_start(GTK_BOX(lblbx), entry, TRUE, TRUE, 0);
	gtk_widget_show(lblbx);

	frame = gtk_frame_new(label);
		gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
		gtk_container_add(GTK_CONTAINER(frame), lblbx);
	gtk_widget_show(frame);

	dlgstf1 = GTK_DIALOG(dlg)->vbox;
		gtk_box_pack_start(GTK_BOX(dlgstf1), frame, TRUE, TRUE, 0);
	gtk_widget_show(dlgstf1);

		gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
					  GTK_SIGNAL_FUNC(interfunc),
					  GTK_OBJECT(dlg));
		gtk_signal_connect_object(GTK_OBJECT(button1), "clicked",
					  GTK_SIGNAL_FUNC(interfunc),
					  GTK_OBJECT(dlg));
		gtk_signal_connect_object(GTK_OBJECT(button2), "clicked",
					  GTK_SIGNAL_FUNC(gtk_widget_destroy),
					  GTK_OBJECT(dlg));
		gtk_signal_connect_object(GTK_OBJECT(dlg), "destroy",
					  GTK_SIGNAL_FUNC(gtk_widget_destroy),
					  GTK_OBJECT(dlg));

		gtk_object_set_user_data(GTK_OBJECT(dlg), (gpointer) hexdat);
	gtk_widget_show(dlg);

	hexdat->i = data;
	hexdat->ent = entry;
	hexdat->func = func;
	hexdat->edata = data2;
	hexdat->maxlen = maxlen;

	gtk_widget_grab_focus(entry);
}

