diff --git a/gtk3/console_window.c b/gtk3/console_window.c new file mode 100644 index 0000000..d8ee71f --- /dev/null +++ b/gtk3/console_window.c @@ -0,0 +1,288 @@ +#include "console_window.h" +#include "util.h" +#include + +struct _ConsoleWindow { + GtkWindowClass parent_class; + + GtkEntry *input; + GtkTextView *output; + GtkTextView *sidebar_input; + GtkTextView *sidebar_output; + + GAsyncQueue *input_queue; + GAsyncQueue *output_queue; + + bool should_clear; + bool log_to_sidebar; + bool clear_sidebar; + + GList *command_history; +}; + +G_DEFINE_TYPE(ConsoleWindow, console_window, GTK_TYPE_WINDOW); + +typedef struct { + const char *message; + GB_log_attributes attributes; + bool sidebar; +} AttributedMessage; + +static void console_window_init(ConsoleWindow *self) { + gtk_widget_init_template(GTK_WIDGET(self)); + + GtkTextBuffer *text_buf = gtk_text_view_get_buffer(self->output); + GtkTextTagTable *tag_table = gtk_text_buffer_get_tag_table(text_buf); + + gtk_text_buffer_create_tag(text_buf, "bold", "weight", PANGO_WEIGHT_BOLD, NULL); + gtk_text_buffer_create_tag(text_buf, "underline", "underline", PANGO_UNDERLINE_SINGLE, "underline-set", true, NULL); + gtk_text_buffer_create_tag(text_buf, "dashed_underline", "underline", PANGO_UNDERLINE_DOUBLE, "underline-set", true, NULL); + + gtk_text_view_set_buffer( + self->sidebar_output, + gtk_text_buffer_new(tag_table) + ); + + gtk_text_buffer_set_text(gtk_text_view_get_buffer(self->sidebar_input), "registers\nbacktrace\n", -1); + + self->input_queue = g_async_queue_new(); + self->output_queue = g_async_queue_new(); + self->log_to_sidebar = false; + self->clear_sidebar = false; + self->command_history = NULL; +} + +static void console_window_realize(GtkWidget *widget) { + ConsoleWindow *self = (ConsoleWindow *)widget; + + GTK_WIDGET_CLASS(console_window_parent_class)->realize(widget); +} + +// Takes ownership of message +static void log_simple(ConsoleWindow *self, const char *message) { + AttributedMessage *attr_msg = g_new(AttributedMessage, 1); + attr_msg->message = message; + attr_msg->attributes = 0; + attr_msg->sidebar = false; + + g_async_queue_push(self->output_queue, attr_msg); +} + +// TODO: Use command history (arrow key (↑, ↓) events) +static void on_input(GtkEntry *input, ConsoleWindow *self) { + const gchar *text_ptr = gtk_entry_get_text(input); + const gchar *text = NULL; + + if (g_strcmp0("", text_ptr) == 0) { + GList *last = g_list_last(self->command_history); + if (last) text = last->data; + } + else { + text = text_ptr; + } + + if (text) { + GList *last = g_list_last(self->command_history); + + // Add command to queue unless it was the last command issued + if (!last || g_strcmp0(last->data, text) != 0) { + self->command_history = g_list_append(self->command_history, g_strdup(text)); + } + + g_async_queue_push(self->input_queue, (gpointer) g_strdup(text)); + gtk_entry_set_text(self->input, ""); + } +} + +static void update_sidebar(ConsoleWindow *self, GB_gameboy_t *gb) { + if (!GB_debugger_is_stopped(gb)) { + return; + } + + GtkTextBuffer *text_buf = gtk_text_view_get_buffer(self->sidebar_input); + gint line_count = gtk_text_buffer_get_line_count(text_buf); + + self->log_to_sidebar = true; + self->clear_sidebar = true; + + for (unsigned line = 0; line < line_count; ++line) { + GtkTextIter start_iter; + GtkTextIter end_iter; + gunichar ch; + + gtk_text_buffer_get_iter_at_line(text_buf, &start_iter, line); + end_iter = start_iter; + + do { + ch = gtk_text_iter_get_char(&end_iter); + if (!gtk_text_iter_forward_char(&end_iter)) { + break; + } + } + while (ch != '\n'); + + gchar *cmd = gtk_text_buffer_get_text(text_buf, &start_iter, &end_iter, false); + g_strchug(cmd); // trim leading whitespace + g_strchomp(cmd); // trim trailing whitespace + + if (g_strcmp0("", cmd) != 0) { + char *duped = g_strdup(cmd); + GB_attributed_log(gb, GB_LOG_BOLD, "%s:\n", duped); + GB_debugger_execute_command(gb, duped); + GB_log(gb, "\n"); + g_free(duped); + } + + g_free(cmd); + } + + self->log_to_sidebar = false; +} + +static gboolean console_window_draw(GtkWidget *widget, cairo_t *cr) { + ConsoleWindow *self = (ConsoleWindow *)widget; + GtkTextBuffer *main_text_buf = gtk_text_view_get_buffer(self->output); + GtkTextBuffer *sidebar_text_buf = gtk_text_view_get_buffer(self->sidebar_output); + + if (self->should_clear) { + gtk_text_buffer_set_text(main_text_buf, "", -1); + gtk_text_buffer_set_text(sidebar_text_buf, "", -1); + + // clear pending log messages + while (g_async_queue_try_pop(self->output_queue)); + + self->should_clear = false; + } + else { + GtkTextIter iter; + GtkTextIter start; + AttributedMessage *attr_msg = NULL; + + GtkTextIter main_scroll_iter; + bool scroll_main = false; + + GtkTextIter sidebar_scroll_iter; + bool scroll_sidebar = false; + + if (self->clear_sidebar) { + gtk_text_buffer_set_text(sidebar_text_buf, "", -1); + self->clear_sidebar = false; + } + + while ((attr_msg = g_async_queue_try_pop(self->output_queue))) { + GtkTextBuffer *text_buf = attr_msg->sidebar? sidebar_text_buf : main_text_buf; + + gtk_text_buffer_get_end_iter(text_buf, &iter); + GtkTextMark *start_mark = gtk_text_buffer_create_mark(text_buf, NULL, &iter, true); + + // give ownership of message to the text buffer + gtk_text_buffer_insert(text_buf, &iter, attr_msg->message, -1); + gtk_text_buffer_get_iter_at_mark(text_buf, &start, start_mark); + + if (attr_msg->attributes & GB_LOG_BOLD) { + gtk_text_buffer_apply_tag_by_name(text_buf, "bold", &start, &iter); + } + + if (attr_msg->attributes & GB_LOG_DASHED_UNDERLINE) { + gtk_text_buffer_apply_tag_by_name(text_buf, "dashed_underline", &start, &iter); + } + + if (attr_msg->attributes & GB_LOG_UNDERLINE) { + gtk_text_buffer_apply_tag_by_name(text_buf, "underline", &start, &iter); + } + + gtk_text_buffer_delete_mark(text_buf, start_mark); + + if (attr_msg->sidebar) { + scroll_sidebar = true; + sidebar_scroll_iter = iter; + } + else { + scroll_main = true; + main_scroll_iter = iter; + } + + g_free(attr_msg); + } + + if (scroll_main) { + scroll_to_bottom(self->output, gtk_text_buffer_create_mark(main_text_buf, NULL, &main_scroll_iter, true)); + } + + if (scroll_sidebar) { + scroll_to_bottom(self->sidebar_output, gtk_text_buffer_create_mark(sidebar_text_buf, NULL, &sidebar_scroll_iter, true)); + } + } + + return GTK_WIDGET_CLASS(console_window_parent_class)->draw(widget, cr); +} + +static void console_window_class_init(ConsoleWindowClass *class) { + gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class), RESOURCE_PREFIX "ui/console_window.ui"); + + gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), ConsoleWindow, input); + gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), ConsoleWindow, output); + gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), ConsoleWindow, sidebar_input); + gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), ConsoleWindow, sidebar_output); + + gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_input); + + GTK_WIDGET_CLASS(class)->realize = console_window_realize; + GTK_WIDGET_CLASS(class)->draw = console_window_draw; +} + +ConsoleWindow *console_window_new(void) { + return g_object_new(CONSOLE_WINDOW_TYPE, NULL); +} + +// This function gets called every VBlank while the emulation is running. +char *console_get_async_input(ConsoleWindow *self, GB_gameboy_t *gb) { + self->clear_sidebar = true; + + char *command = (char *)g_async_queue_try_pop(self->input_queue); + + if (command) { + gchar *msg = g_strdup_printf("> %s\n", command); + log_simple(self, msg); + } + + return command; +} + +// This will only be called if the debugger is in stopped mode (after a breakpoint hit for example), +// thus we block the emulation thread until input is available. +char *console_get_sync_input(ConsoleWindow *self, GB_gameboy_t *gb) { + update_sidebar(self, gb); + + char *command = (char *)g_async_queue_pop(self->input_queue); + + if (command) { + gchar *msg = g_strdup_printf("> %s\n", command); + log_simple(self, msg); + } + + return command; +} + +// Queues a message to be logged to the console +void console_log(ConsoleWindow *self, const char *message, GB_log_attributes attributes) { + if (!message || g_str_equal("", message)) return; + + AttributedMessage *attr_msg = g_new(AttributedMessage, 1); + attr_msg->message = g_strdup(message); + attr_msg->attributes = attributes; + attr_msg->sidebar = self->log_to_sidebar; + + g_async_queue_push(self->output_queue, attr_msg); + + // mark as dirty + gtk_widget_queue_draw(GTK_WIDGET(self)); +} + +// Marks the console as to be cleared on the next redraw +void console_clear(ConsoleWindow *self) { + self->should_clear = true; + + // mark as dirty + gtk_widget_queue_draw(GTK_WIDGET(self)); +} diff --git a/gtk3/console_window.h b/gtk3/console_window.h new file mode 100644 index 0000000..c97468c --- /dev/null +++ b/gtk3/console_window.h @@ -0,0 +1,15 @@ +#ifndef console_window_h +#define console_window_h + +#include +#include + +#define CONSOLE_WINDOW_TYPE (console_window_get_type()) +G_DECLARE_FINAL_TYPE(ConsoleWindow, console_window, SAMEBOY, CONSOLE_WINDOW, GtkWindow) + +ConsoleWindow *console_window_new(void); +char *console_get_async_input(ConsoleWindow *self, GB_gameboy_t *gb); +char *console_get_sync_input(ConsoleWindow *self, GB_gameboy_t *gb); +void console_log(ConsoleWindow *self, const char *message, GB_log_attributes attributes); +void console_clear(ConsoleWindow *self); +#endif \ No newline at end of file diff --git a/gtk3/main.c b/gtk3/main.c index 011d211..b2af5ed 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -14,6 +14,7 @@ #include "check_menu_radio_group.h" #include "gb_screen.h" +#include "console_window.h" #include "preferences_window.h" #include "vram_viewer_window.h" @@ -52,10 +53,6 @@ static GuiData gui_data = { .stopping = false, .stopped = false, - .in_sync_input = false, - .log_to_sidebar = false, - .should_clear_sidebar = false, - .audio_initialized = false, .border_mode_changed = false, @@ -355,199 +352,6 @@ static void rumble_callback(GB_gameboy_t *gb, double amp) { } } -static gboolean clear_sidebar(void) { - GtkTextView *sidebar_output = builder_get(GTK_TEXT_VIEW, "console_sidebar_output"); - GtkTextBuffer *sidebar_output_text_buf = gtk_text_view_get_buffer(sidebar_output); - gtk_text_buffer_set_text(sidebar_output_text_buf, "", -1); - - return false; -} - -static gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark) { - GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview); - GtkTextIter iter; - - gtk_text_buffer_get_end_iter(buffer, &iter); - gtk_text_iter_set_line_offset(&iter, 0); - - gtk_text_buffer_move_mark(buffer, mark, &iter); - gtk_text_view_scroll_to_mark(textview, mark, 0.0, true, 0.0, 0.10); - - gtk_text_buffer_delete_mark(buffer, mark); - - return true; -} - -static gboolean append_pending_output(void) { - g_rec_mutex_lock(&gui_data.console_output_lock); - - if (gui_data.should_clear_sidebar) { - clear_sidebar(); - gui_data.should_clear_sidebar = false; - } - - if (gtk_text_buffer_get_char_count(gui_data.pending_console_output) > 0) { - GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, gui_data.log_to_sidebar? "console_sidebar_output" : "console_screen"); - GtkTextBuffer *text_buf = gtk_text_view_get_buffer(text_view); - GtkTextIter start; - GtkTextIter end; - gtk_text_buffer_get_start_iter(gui_data.pending_console_output, &start); - gtk_text_buffer_get_end_iter(gui_data.pending_console_output, &end); - - GtkTextIter iter; - gtk_text_buffer_get_end_iter(text_buf, &iter); - gtk_text_buffer_insert_range(text_buf, &iter, &start, &end); - - scroll_to_bottom(text_view, gtk_text_buffer_create_mark(text_buf, NULL, &iter, true)); - - gtk_text_buffer_set_text(gui_data.pending_console_output, "", -1); - } - - g_rec_mutex_unlock(&gui_data.console_output_lock); - - return false; -} - -static gboolean update_debugger_sidebar(GB_gameboy_t *gb) { - if (!GB_debugger_is_stopped(gb)) { - return false; - } - - if (gui_data.main_thread != g_thread_self()) { - g_idle_add((GSourceFunc) update_debugger_sidebar, gb); - return false; - } - - g_rec_mutex_lock(&gui_data.console_output_lock); - gui_data.should_clear_sidebar = true; - append_pending_output(); - gui_data.log_to_sidebar = true; - g_rec_mutex_unlock(&gui_data.console_output_lock); - - GtkTextView *sidebar_input = builder_get(GTK_TEXT_VIEW, "console_sidebar_input"); - GtkTextBuffer *sidebar_input_text_buf = gtk_text_view_get_buffer(sidebar_input); - - gint line_count = gtk_text_buffer_get_line_count(sidebar_input_text_buf); - - for (unsigned line = 0; line < line_count; ++line) { - GtkTextIter start_iter; - GtkTextIter end_iter; - gunichar ch; - - gtk_text_buffer_get_iter_at_line(sidebar_input_text_buf, &start_iter, line); - end_iter = start_iter; - - do { - ch = gtk_text_iter_get_char(&end_iter); - if (!gtk_text_iter_forward_char(&end_iter)) { - break; - } - } - while (ch != '\n'); - - gchar *cmd = gtk_text_buffer_get_text(sidebar_input_text_buf, &start_iter, &end_iter, false); - g_strchug(cmd); // trim leading whitespace - g_strchomp(cmd); // trim trailing whitespace - - if (g_strcmp0("", cmd) != 0) { - char *duped = g_strdup(cmd); - GB_attributed_log(gb, GB_LOG_BOLD, "%s:\n", duped); - GB_debugger_execute_command(gb, duped); - GB_log(gb, "\n"); - g_free(duped); - } - - g_free(cmd); - } - - g_rec_mutex_lock(&gui_data.console_output_lock); - append_pending_output(); - gui_data.log_to_sidebar = false; - g_rec_mutex_unlock(&gui_data.console_output_lock); - - return false; -} - -static void console_log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes) { - g_rec_mutex_lock(&gui_data.console_output_lock); - - if (string != NULL && !g_str_equal("", string)) { - GtkTextIter iter; - GtkTextIter start; - - // Append attributed text to "gui_data.pending_console_output" GtkTextBuffer - gtk_text_buffer_get_end_iter(gui_data.pending_console_output, &iter); - GtkTextMark *start_mark = gtk_text_buffer_create_mark(gui_data.pending_console_output, NULL, &iter, true); - gtk_text_buffer_insert(gui_data.pending_console_output, &iter, g_strdup(string), -1); - gtk_text_buffer_get_iter_at_mark(gui_data.pending_console_output, &start, start_mark); - - if (attributes & GB_LOG_BOLD) { - gtk_text_buffer_apply_tag_by_name(gui_data.pending_console_output, "bold", &start, &iter); - } - - if (attributes & GB_LOG_DASHED_UNDERLINE) { - gtk_text_buffer_apply_tag_by_name(gui_data.pending_console_output, "dashed_underline", &start, &iter); - } - - if (attributes & GB_LOG_UNDERLINE) { - gtk_text_buffer_apply_tag_by_name(gui_data.pending_console_output, "underline", &start, &iter); - } - - gtk_text_buffer_delete_mark(gui_data.pending_console_output, start_mark); - - g_idle_add((GSourceFunc) append_pending_output, NULL); - } - - g_rec_mutex_unlock(&gui_data.console_output_lock); -} - -// Console TODO: -// TODO: clear sidebar when switching to async mode -// TODO: Command history (up / down arrow in input) -// TODO: reverse search of commands -// TODO: search in output -static char *sync_console_input(GB_gameboy_t *gb) { - update_debugger_sidebar(gb); - console_log(gb, "> ", 0); - gui_data.in_sync_input = true; - - g_mutex_lock(&gui_data.debugger_input_mutex); - g_cond_wait(&gui_data.debugger_input_cond, &gui_data.debugger_input_mutex); - - gchar *input = NULL; - const gchar *_input = g_ptr_array_index(gui_data.debugger_input_queue, 0); - input = g_strdup(_input); - gpointer ptr = g_ptr_array_remove_index(gui_data.debugger_input_queue, 0); - if (ptr) g_free(ptr); - - g_mutex_unlock(&gui_data.debugger_input_mutex); - - gui_data.in_sync_input = false; - - return input; -} - -static char *async_console_input(GB_gameboy_t *gb) { - // TODO: This is rather ugly - g_idle_add((GSourceFunc) clear_sidebar, NULL); - - if (gui_data.debugger_input_queue->len == 0) return NULL; - - g_mutex_lock(&gui_data.debugger_input_mutex); - - gchar *input = NULL; - const gchar *_input = g_ptr_array_index(gui_data.debugger_input_queue, 0); - if (_input) { - input = g_strdup(_input); - gpointer ptr = g_ptr_array_remove_index(gui_data.debugger_input_queue, 0); - if (ptr) g_free(ptr); - } - - g_mutex_unlock(&gui_data.debugger_input_mutex); - - return input; -} - // Creating these items in the UI defintion files was buggy in some desktop // environments and the manual call of `g_signal_connect` was needed anyway // because the UI definition can’t define string arguments for signal handlers. @@ -867,31 +671,47 @@ static void load_boot_rom(GB_gameboy_t *gb, GB_boot_rom_t type) { } } +static char *wrapped_console_get_async_input(GB_gameboy_t *gb) { + return console_get_async_input(gui_data.console, gb); +} + +static char *wrapped_console_get_sync_input(GB_gameboy_t *gb) { + return console_get_sync_input(gui_data.console, gb); +} + +static void wrapped_console_log(GB_gameboy_t *gb, const char *message, GB_log_attributes attributes) { + console_log(gui_data.console, message, attributes); +} + static void init(void) { if (GB_is_inited(&gb)) return; GB_init(&gb, config_get_model_type(&gui_data)); GB_set_vblank_callback(&gb, vblank); - GB_set_pixels_output(&gb, gb_screen_get_current_buffer(gui_data.screen)); GB_set_rgb_encode_callback(&gb, rgb_encode); - GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); + + GB_set_pixels_output(&gb, gb_screen_get_current_buffer(gui_data.screen)); GB_set_color_correction_mode(&gb, config_get_color_correction_mode()); - GB_set_highpass_filter_mode(&gb, config_get_highpass_mode()); - GB_set_rewind_length(&gb, config.emulation.rewind_duration); - GB_set_update_input_hint_callback(&gb, handle_events); - GB_apu_set_sample_callback(&gb, gb_audio_callback); - GB_set_input_callback(&gb, sync_console_input); - GB_set_async_input_callback(&gb, async_console_input); - GB_set_log_callback(&gb, console_log); - GB_set_boot_rom_load_callback(&gb, load_boot_rom); - - GB_set_rumble_callback(&gb, rumble_callback); - GB_set_rumble_mode(&gb, config_get_rumble_mode()); - if (config_get_display_border_mode() <= GB_BORDER_ALWAYS) { GB_set_border_mode(&gb, config_get_display_border_mode()); } + + GB_apu_set_sample_callback(&gb, gb_audio_callback); + + GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); + GB_set_highpass_filter_mode(&gb, config_get_highpass_mode()); + + GB_set_log_callback(&gb, wrapped_console_log); + GB_set_input_callback(&gb, wrapped_console_get_sync_input); + GB_set_async_input_callback(&gb, wrapped_console_get_async_input); + + GB_set_boot_rom_load_callback(&gb, load_boot_rom); + GB_set_update_input_hint_callback(&gb, handle_events); + GB_set_rumble_callback(&gb, rumble_callback); + + GB_set_rumble_mode(&gb, config_get_rumble_mode()); + GB_set_rewind_length(&gb, config.emulation.rewind_duration); } static void reset(void) { @@ -1170,11 +990,11 @@ static void startup(GApplication *app, gpointer null_ptr) { init_config(app, gui_data.cli_options.config_path, &gui_data.config_modification_date); gui_data.screen = gb_screen_new(gui_data.cli_options.force_software_renderer); + gui_data.console = console_window_new(); gui_data.preferences = preferences_window_new(&gb); gui_data.vram_viewer = vram_viewer_window_new(); gui_data.memory_viewer = GTK_WINDOW(get_object("memory_viewer")); - gui_data.console = GTK_WINDOW(get_object("console")); gui_data.printer = GTK_WINDOW(get_object("printer")); if (config.audio.sample_rate == -1) { @@ -1322,40 +1142,12 @@ static void connect_signal_handlers(GApplication *app) { g_signal_connect(gui_data.preferences, "pref-update::audio-sample-rate", G_CALLBACK(on_preferences_notify_sample_rate), NULL); } -static void setup_console(void) { - GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, "console_screen"); - GtkTextBuffer *text_buf = gtk_text_view_get_buffer(text_view); - - gtk_text_view_set_buffer( - builder_get(GTK_TEXT_VIEW, "console_sidebar_output"), - gtk_text_buffer_new(gtk_text_buffer_get_tag_table(text_buf)) - ); - - gtk_text_buffer_create_tag(text_buf, "bold", "weight", PANGO_WEIGHT_BOLD, NULL); - gtk_text_buffer_create_tag(text_buf, "underline", "underline", PANGO_UNDERLINE_SINGLE, "underline-set", true, NULL); - gtk_text_buffer_create_tag(text_buf, "dashed_underline", "underline", PANGO_UNDERLINE_DOUBLE, "underline-set", true, NULL); - - g_mutex_init(&gui_data.debugger_input_mutex); - g_cond_init(&gui_data.debugger_input_cond); - g_rec_mutex_init(&gui_data.console_output_lock); - - if (!gui_data.debugger_input_queue) { - gui_data.debugger_input_queue = g_ptr_array_sized_new(4); - } - - if (!gui_data.pending_console_output) { - gui_data.pending_console_output = gtk_text_buffer_new(gtk_text_buffer_get_tag_table(text_buf)); - } -} - // This function gets called when the GApplication gets activated, i.e. it is ready to show widgets. static void activate(GApplication *app, gpointer null_ptr) { init_audio(); init_controllers(); connect_signal_handlers(app); - // create_canvas(); - setup_console(); if (gui_data.cli_options.fullscreen) { gtk_window_fullscreen(GTK_WINDOW(gui_data.main_window)); @@ -1401,16 +1193,17 @@ static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer gtk_widget_hide(GTK_WIDGET(dialog)); } + +// app.preferences GAction +// Opens the preferences window +static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app) { + gtk_widget_show_all(GTK_WIDGET(gui_data.preferences)); +} + // app.show_console GAction // Opens the console static void activate_show_console(GSimpleAction *action, GVariant *parameter, gpointer app) { - if (gui_data.debugger_input_queue) { - while (gui_data.debugger_input_queue->len) { - g_ptr_array_remove_index_fast(gui_data.debugger_input_queue, gui_data.debugger_input_queue->len - 1); - } - } - - gtk_widget_show_all(builder_get(GTK_WIDGET, "console")); + gtk_widget_show_all(GTK_WIDGET(gui_data.console)); } // app.open_gtk_debugger GAction @@ -1431,6 +1224,12 @@ static void activate_open_vram_viewer(GSimpleAction *action, GVariant *parameter gtk_widget_show_all(GTK_WIDGET(gui_data.vram_viewer)); } +// app.clear_console GAction +// Clears the debugger console +static void activate_clear_console(GSimpleAction *action, GVariant *parameter, gpointer app) { + console_clear(gui_data.console); +} + // Closes a ROM static void close_rom(void) { stop(); @@ -1478,30 +1277,12 @@ static void activate_close(GSimpleAction *action, GVariant *parameter, gpointer close_rom(); } -// app.preferences GAction -// Opens the preferences window -static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app) { - gtk_widget_show_all(GTK_WIDGET(gui_data.preferences)); -} - // app.quit GAction // Exits the application static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer app) { quit(); } -// app.clear_console GAction -// Clears the debugger console -static void activate_clear_console(GSimpleAction *action, GVariant *parameter, gpointer app) { - g_rec_mutex_lock(&gui_data.console_output_lock); - - GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, "console_screen"); - GtkTextBuffer *text_buf = gtk_text_view_get_buffer(text_view); - gtk_text_buffer_set_text(text_buf, "", -1); - - g_rec_mutex_unlock(&gui_data.console_output_lock); -} - static void on_mute_changed(GSimpleAction *action, GVariant *value, gpointer user_data_ptr) { config.audio.muted = g_variant_get_boolean(value); @@ -1543,35 +1324,6 @@ G_MODULE_EXPORT void on_open_recent_activate(GtkRecentChooser *chooser, gpointer } } -G_MODULE_EXPORT void console_on_enter(GtkWidget *w, gpointer user_data_ptr) { - GtkEntry *input = GTK_ENTRY(w); - const gchar *_text = gtk_entry_get_text(input); - gchar *text = g_strdup(_text); - - if (g_strcmp0("", text) == 0 && g_strcmp0("", gui_data.last_console_input) < 0) { - text = g_strdup(gui_data.last_console_input); - } - else if (text) { - if (gui_data.last_console_input != NULL) g_free(gui_data.last_console_input); - gui_data.last_console_input = g_strdup(text); - } - - if (!gui_data.in_sync_input) { - console_log(&gb, "> ", 0); - } - - console_log(&gb, text, 0); - console_log(&gb, "\n", 0); - - g_mutex_lock(&gui_data.debugger_input_mutex); - g_ptr_array_add(gui_data.debugger_input_queue, (gpointer)text); - g_cond_signal(&gui_data.debugger_input_cond); - g_mutex_unlock(&gui_data.debugger_input_mutex); - - // clear input - gtk_entry_set_text(input, ""); -} - int main(int argc, char *argv[]) { gui_data.main_thread = g_thread_self(); diff --git a/gtk3/resources/ui/console_window.ui b/gtk3/resources/ui/console_window.ui new file mode 100644 index 0000000..f18c2b6 --- /dev/null +++ b/gtk3/resources/ui/console_window.ui @@ -0,0 +1,202 @@ + + + + + + + + + + + diff --git a/gtk3/resources/ui/window.ui b/gtk3/resources/ui/window.ui index 96852d0..23d2d9c 100644 --- a/gtk3/resources/ui/window.ui +++ b/gtk3/resources/ui/window.ui @@ -72,173 +72,6 @@ Maximilian Mader https://github.com/max-m - - False - Debug Console - 920 - 400 - - - True - False - vertical - - - True - False - - - True - True - in - 600 - 376 - 600 - 376 - - - True - True - False - word - 5 - 5 - 5 - 5 - False - False - True - - - - - - - True - True - 0 - - - - - 320 - True - False - vertical - - - True - True - in - 320 - 80 - - - True - True - word - 5 - 5 - 5 - 5 - False - True - - - - - - - False - True - 0 - - - - - True - True - in - - - True - True - False - word - 5 - 5 - 5 - 5 - False - True - - - - - - - True - True - 1 - - - - - False - True - 1 - - - - - - True - True - 0 - - - - - True - True - 3 - 3 - Console input - - - - False - True - 1 - - - - - - - - - - False Memory Viewer diff --git a/gtk3/sameboy.gresource.xml b/gtk3/sameboy.gresource.xml index 79256fe..880e640 100644 --- a/gtk3/sameboy.gresource.xml +++ b/gtk3/sameboy.gresource.xml @@ -2,6 +2,7 @@ ui/window.ui + ui/console_window.ui ui/preferences_window.ui ui/vram_viewer_window.ui