From 82f6a5ef2b2ca2ec31afabdca9d0141bc732c6e7 Mon Sep 17 00:00:00 2001
From: Marvin Borner
Date: Mon, 30 Jan 2023 23:16:44 +0100
Subject: More gui => more bugs

---
 inc/cpu.h  |   5 ++-
 inc/gui.h  |   5 ++-
 src/cpu.c  |  22 ++++++++++-
 src/gui.c  | 125 ++++++++++++++++++++++++++++++++++++++++++-------------------
 src/main.c |   3 +-
 5 files changed, 115 insertions(+), 45 deletions(-)

diff --git a/inc/cpu.h b/inc/cpu.h
index ca85a2f..e0caf50 100644
--- a/inc/cpu.h
+++ b/inc/cpu.h
@@ -6,9 +6,10 @@
 #include <err.h>
 
 struct cpu_interface {
-	void (*reg_names)(const char *names, int n);
+	void (*reg_names)(const char *names[], int n);
 	void (*reg_update)(int reg, uint64_t val);
-	void (*instr_done)(char *instr);
+	void (*instr_push)(char *instr);
+	void (*instr_pop)(void);
 };
 
 enum registers {
diff --git a/inc/gui.h b/inc/gui.h
index e8a583d..3dfcc1b 100644
--- a/inc/gui.h
+++ b/inc/gui.h
@@ -9,9 +9,10 @@ struct gui_interface {
 	err (*step_prev)(void);
 };
 
-void gui_reg_names(const char *names, int n);
+void gui_reg_names(const char *names[], int n);
 void gui_reg_update(int reg, uint64_t value);
-void gui_instr_done(char *instr);
+void gui_instr_push(char *instr);
+void gui_instr_pop(void);
 
 void gui_register_interface(struct gui_interface *gui);
 void gui_init(void);
diff --git a/src/cpu.c b/src/cpu.c
index 21b9f19..bce36a2 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -104,6 +104,13 @@ static err (*neg_instructions[256])(void);
 static uint64_t regs[REGISTERS_COUNT] = { 0 };
 static struct rip_history *rip_history;
 
+static char instruction_response_factory[256] = { 0 };
+
+static const char *register_names[REGISTERS_COUNT] = {
+	"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
+	"R8",  "R9",  "R10", "R11", "R12", "R13", "R14", "R15",
+};
+
 static void print_state(void)
 {
 	logln("rip=%x, rax=%x, rcx=%x, rdx=%x, rbx=%x, rsp=%x, rbp=%x, rsi=%x, rdi=%x,\nr8=%x, r9=%x, r10=%x, r11=%x, r12=%x, r13=%x, r14=%x, r15=%x",
@@ -129,6 +136,7 @@ static err pos_opcode(void)
 	uint8_t op = U8();
 	// TODO: is_*, j*
 	if (op == 0x05) {
+		sprintf(instruction_response_factory, "syscall");
 		return linux_call();
 	}
 	return ERR;
@@ -137,7 +145,10 @@ static err pos_opcode(void)
 static err pos_mov_r32_rm32(void)
 {
 	uint8_t modrm = U8();
-	SET_R32(REG(), GET_RM32());
+	uint8_t reg = REG();
+	uint32_t val = GET_RM32();
+	sprintf(instruction_response_factory, "mov %s, %x", register_names[reg],
+		val);
 	return OK;
 }
 
@@ -145,12 +156,16 @@ static err pos_mov_r32_imm32(void)
 {
 	rip--;
 	uint8_t reg = U8() - 0xb8;
-	SET_R32(reg, U32());
+	uint32_t val = U32();
+	SET_R32(reg, val);
+	sprintf(instruction_response_factory, "mov %s, %#x",
+		register_names[reg], val);
 	return OK;
 }
 
 static err pos_nop(void)
 {
+	sprintf(instruction_response_factory, "nop");
 	return OK;
 }
 
@@ -167,6 +182,7 @@ static err pos_int(void)
 
 static void initialize(void)
 {
+	interface->reg_names(register_names, REGISTERS_COUNT);
 	for (int i = 0; i < 256; i++) {
 		pos_instructions[i] = pos_unknown_instruction;
 		neg_instructions[i] = neg_unknown_instruction;
@@ -220,6 +236,7 @@ err cpu_next(void)
 		return END;
 	logln("%x", instr);
 	err ret = pos_instructions[instr]();
+	interface->instr_push(instruction_response_factory);
 	print_state();
 
 	struct rip_history *next = malloc(sizeof(*next));
@@ -239,6 +256,7 @@ err cpu_prev(void)
 	if (!instr)
 		return ERR;
 	err ret = neg_instructions[instr]();
+	interface->instr_pop();
 	print_state();
 
 	free(rip_history);
diff --git a/src/gui.c b/src/gui.c
index 297ff6f..38d983f 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -9,7 +9,10 @@ enum stepper_response_type {
 };
 
 static struct gui_interface *interface;
+static GtkWindow *main;
+static GtkStringList *execution_list;
 
+// TODO: Either beautify or use InfoBar
 static void error_dialog(GtkWindow *parent, const char *msg)
 {
 	GtkWidget *dialog = gtk_dialog_new_with_buttons(
@@ -24,61 +27,102 @@ static void error_dialog(GtkWindow *parent, const char *msg)
 	gtk_widget_show(dialog);
 }
 
-static void stepper_response(GtkWidget *widget, enum stepper_response_type type)
+static void stepper_handle_response(err ret)
 {
-	err ret = OK;
-
-	switch (type) {
-	case STEP_PREV:
-		ret = interface->step_prev();
-		break;
-	case STEP_NEXT:
-		ret = interface->step_next();
-		break;
-	default:
-		break;
-	}
-
 	if (ret == END || ret == ERR) {
-		error_dialog(GTK_WINDOW(widget),
+		error_dialog(main,
 			     ret == END ? "Reached end" : "An error occured");
 	}
 }
 
-static void init_stepper_dialog(GtkWindow *parent)
+static void stepper_next(void)
 {
-	GtkWidget *stepper = gtk_dialog_new_with_buttons(
-		"Stepper", parent,
-		GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, "Previous",
-		1, "Next", 2, NULL);
+	stepper_handle_response(interface->step_next());
+}
 
-	GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(stepper));
-	GtkWidget *label = gtk_label_new("Stepper");
+static void stepper_prev(void)
+{
+	stepper_handle_response(interface->step_prev());
+}
 
-	g_signal_connect_swapped(stepper, "response",
-				 G_CALLBACK(stepper_response), stepper);
+static void init_menu(void)
+{
+	GtkWidget *header = gtk_header_bar_new();
 
-	gtk_box_append(GTK_BOX(content), label);
-	gtk_widget_show(stepper);
+	GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+	gtk_widget_add_css_class(box, "linked");
+
+	GtkWidget *prev = gtk_button_new_from_icon_name("go-previous-symbolic");
+	gtk_box_append(GTK_BOX(box), prev);
+
+	GtkWidget *next = gtk_button_new_from_icon_name("go-next-symbolic");
+	gtk_box_append(GTK_BOX(box), next);
+
+	g_signal_connect(prev, "clicked", G_CALLBACK(stepper_prev), prev);
+	g_signal_connect(next, "clicked", G_CALLBACK(stepper_next), next);
+
+	gtk_header_bar_pack_end(GTK_HEADER_BAR(header), box);
+	gtk_window_set_titlebar(main, header);
+}
+
+static void setup_execution_list(GtkSignalListItemFactory *self,
+				 GtkListItem *item, gpointer data)
+{
+	(void)self;
+	(void)data;
+	GtkWidget *test = gtk_label_new(0);
+	gtk_label_set_xalign(GTK_LABEL(test), 0);
+	gtk_list_item_set_child(item, test);
 }
 
-static void init_execution_window(GtkApplication *app)
+static void bind_execution_list(GtkSignalListItemFactory *self,
+				GtkListItem *item, gpointer data)
 {
-	GtkWidget *execution = gtk_application_window_new(app);
-	gtk_window_set_title(GTK_WINDOW(execution), "Execution");
-	gtk_window_set_default_size(GTK_WINDOW(execution), 200, 200);
-	gtk_widget_show(execution);
+	(void)self;
+	(void)data;
+	GtkWidget *test = gtk_list_item_get_child(item);
+	GtkStringObject *str = gtk_list_item_get_item(item);
+	gtk_label_set_text(GTK_LABEL(test), gtk_string_object_get_string(str));
+}
 
-	init_stepper_dialog(GTK_WINDOW(execution));
+static GtkWidget *init_execution_list(void)
+{
+	const char *array[] = { NULL };
+	execution_list = gtk_string_list_new((const char *const *)array);
+	GtkNoSelection *model =
+		gtk_no_selection_new(G_LIST_MODEL(execution_list));
+
+	GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
+	g_signal_connect(factory, "setup", G_CALLBACK(setup_execution_list), 0);
+	g_signal_connect(factory, "bind", G_CALLBACK(bind_execution_list), 0);
+	return gtk_list_view_new(GTK_SELECTION_MODEL(model), factory);
+}
+
+static void init_main_window(GtkApplication *app)
+{
+	main = GTK_WINDOW(gtk_application_window_new(app));
+	gtk_window_set_title(main, "Simsalasim");
+	gtk_window_set_default_size(main, 200, 200);
+
+	GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+	gtk_window_set_child(main, paned);
+
+	GtkWidget *left = init_execution_list();
+	gtk_paned_set_start_child(GTK_PANED(paned), left);
+
+	GtkWidget *right = gtk_label_new("end");
+	gtk_paned_set_end_child(GTK_PANED(paned), right);
 }
 
 static void activate(GtkApplication *app, gpointer user_data)
 {
 	(void)user_data;
-	init_execution_window(app);
+	init_main_window(app);
+	init_menu();
+	gtk_widget_show(GTK_WIDGET(main));
 }
 
-void gui_reg_names(const char *names, int n)
+void gui_reg_names(const char *names[], int n)
 {
 	(void)names;
 	(void)n;
@@ -90,9 +134,16 @@ void gui_reg_update(int reg, uint64_t value)
 	(void)value;
 }
 
-void gui_instr_done(char *instr)
+static int execution_list_length = 0;
+void gui_instr_push(char *instr)
+{
+	gtk_string_list_take(execution_list, instr);
+	execution_list_length++;
+}
+
+void gui_instr_pop(void)
 {
-	(void)instr;
+	gtk_string_list_remove(execution_list, --execution_list_length);
 }
 
 void gui_register_interface(struct gui_interface *gui)
@@ -102,8 +153,6 @@ void gui_register_interface(struct gui_interface *gui)
 
 void gui_init(void)
 {
-	g_object_set(gtk_settings_get_default(),
-		     "gtk-application-prefer-dark-theme", TRUE, NULL);
 	GtkApplication *app = gtk_application_new("de.melvars.simsalasim",
 						  G_APPLICATION_DEFAULT_FLAGS);
 	g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
diff --git a/src/main.c b/src/main.c
index 244b715..7f5ad67 100644
--- a/src/main.c
+++ b/src/main.c
@@ -6,7 +6,8 @@
 static struct cpu_interface cpu = {
 	.reg_names = gui_reg_names,
 	.reg_update = gui_reg_update,
-	.instr_done = gui_instr_done,
+	.instr_push = gui_instr_push,
+	.instr_pop = gui_instr_pop,
 };
 
 static struct gui_interface gui = {
-- 
cgit v1.2.3