[GTK3] Implement debugger console sidebar
This commit is contained in:
parent
a551c09964
commit
66e2e75102
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ build
|
|||||||
# intermediate source files generated at build time
|
# intermediate source files generated at build time
|
||||||
gtk3/sameboy-gtk3-resources.c
|
gtk3/sameboy-gtk3-resources.c
|
||||||
gtk3/resources/gtk3/
|
gtk3/resources/gtk3/
|
||||||
|
gtk3/resources/ui/#*#
|
||||||
|
|
||||||
# temporary backup file
|
# temporary backup file
|
||||||
*.*~
|
*.*~
|
||||||
|
239
gtk3/main.c
239
gtk3/main.c
@ -23,6 +23,8 @@ static SDL_GameController *controller = NULL;
|
|||||||
static SDL_AudioSpec want_aspec, have_aspec;
|
static SDL_AudioSpec want_aspec, have_aspec;
|
||||||
static SDL_AudioDeviceID device_id;
|
static SDL_AudioDeviceID device_id;
|
||||||
|
|
||||||
|
static const GThread *main_thread;
|
||||||
|
|
||||||
static GtkApplication *main_application;
|
static GtkApplication *main_application;
|
||||||
static GtkBuilder *builder;
|
static GtkBuilder *builder;
|
||||||
static GtkGLArea *gl_area;
|
static GtkGLArea *gl_area;
|
||||||
@ -72,12 +74,15 @@ static uint8_t oamHeight;
|
|||||||
|
|
||||||
static uint8_t pressed_buttons;
|
static uint8_t pressed_buttons;
|
||||||
|
|
||||||
|
static GtkTextBuffer *pending_console_output = NULL;
|
||||||
static gboolean in_sync_input = false;
|
static gboolean in_sync_input = false;
|
||||||
static gchar *last_console_input = NULL;
|
static gchar *last_console_input = NULL;
|
||||||
|
static gboolean log_to_sidebar = false;
|
||||||
|
static gboolean should_clear_sidebar = false;
|
||||||
|
|
||||||
static GMutex debugger_input_mutex;
|
static GMutex debugger_input_mutex;
|
||||||
static GCond debugger_input_cond;
|
static GCond debugger_input_cond;
|
||||||
static GMutex console_output_lock;
|
static GRecMutex console_output_lock;
|
||||||
static GPtrArray *debugger_input_queue;
|
static GPtrArray *debugger_input_queue;
|
||||||
|
|
||||||
// List of GActions for the `app` prefix
|
// List of GActions for the `app` prefix
|
||||||
@ -97,9 +102,12 @@ static const GActionEntry app_entries[] = {
|
|||||||
{ "change_model", NULL, "s", "@s 'CGB'", on_model_changed },
|
{ "change_model", NULL, "s", "@s 'CGB'", on_model_changed },
|
||||||
{ "toggle_mute", NULL, NULL, "false", on_mute_changed },
|
{ "toggle_mute", NULL, NULL, "false", on_mute_changed },
|
||||||
{ "pause", NULL, NULL, "false", on_pause_changed },
|
{ "pause", NULL, NULL, "false", on_pause_changed },
|
||||||
|
{ "clear_console", activate_clear_console, NULL, NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
main_thread = g_thread_self();
|
||||||
|
|
||||||
// initialize GB_model_t to invalid value
|
// initialize GB_model_t to invalid value
|
||||||
gui_data.cli_options.model = -1;
|
gui_data.cli_options.model = -1;
|
||||||
gui_data.prev_model = -1;
|
gui_data.prev_model = -1;
|
||||||
@ -245,7 +253,7 @@ void gl_check_realize(GtkWidget *w, gpointer user_data_gptr) {
|
|||||||
else {
|
else {
|
||||||
gdk_gl_context_make_current(context);
|
gdk_gl_context_make_current(context);
|
||||||
int version = epoxy_gl_version();
|
int version = epoxy_gl_version();
|
||||||
|
|
||||||
g_object_run_dispose(G_OBJECT(context));
|
g_object_run_dispose(G_OBJECT(context));
|
||||||
g_object_unref(context);
|
g_object_unref(context);
|
||||||
context = NULL;
|
context = NULL;
|
||||||
@ -278,7 +286,7 @@ static gboolean init_controllers() {
|
|||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
g_warning("Failed to load controller mappings: %s", SDL_GetError());
|
g_warning("Failed to load controller mappings: %s", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
g_bytes_unref(db_f);
|
g_bytes_unref(db_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,7 +371,7 @@ static GB_model_t get_model() {
|
|||||||
else if (g_strcmp0(family, "SGB") == 0) {
|
else if (g_strcmp0(family, "SGB") == 0) {
|
||||||
return get_sgb_model();
|
return get_sgb_model();
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_cgb_model();
|
return get_cgb_model();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +394,13 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) {
|
|||||||
SDL_QueueAudio(device_id, sample, sizeof(*sample));
|
SDL_QueueAudio(device_id, sample, sizeof(*sample));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
static char *sync_console_input(GB_gameboy_t *gb) {
|
||||||
|
update_debugger_sidebar(gb);
|
||||||
console_log(gb, "> ", 0);
|
console_log(gb, "> ", 0);
|
||||||
in_sync_input = true;
|
in_sync_input = true;
|
||||||
|
|
||||||
@ -403,11 +417,6 @@ static char *sync_console_input(GB_gameboy_t *gb) {
|
|||||||
|
|
||||||
in_sync_input = false;
|
in_sync_input = false;
|
||||||
|
|
||||||
// clear sidebar
|
|
||||||
GtkTextView *sidebar_output = builder_get(GTK_TEXT_VIEW, "console_sidebar_output");
|
|
||||||
GtkTextBuffer *sidebar_text_buf = gtk_text_view_get_buffer(sidebar_output);
|
|
||||||
gtk_text_buffer_set_text(sidebar_text_buf, "", -1);
|
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,50 +438,140 @@ static char *async_console_input(GB_gameboy_t *gb) {
|
|||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_console_log(gpointer user_data_gptr) {
|
static void update_debugger_sidebar(GB_gameboy_t *gb) {
|
||||||
LogData *log_data = (LogData *)user_data_gptr;
|
if (!GB_debugger_is_stopped(gb)) {
|
||||||
GB_gameboy_t *gb = log_data->gb;
|
return;
|
||||||
GB_log_attributes attributes = log_data->attributes;
|
}
|
||||||
|
|
||||||
g_mutex_lock(&console_output_lock);
|
if (main_thread != g_thread_self()) {
|
||||||
|
g_idle_add((GSourceFunc) update_debugger_sidebar, gb);
|
||||||
GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, "console_screen");
|
return;
|
||||||
GtkTextBuffer *text_buf = gtk_text_view_get_buffer(text_view);
|
}
|
||||||
|
|
||||||
|
g_rec_mutex_lock(&console_output_lock);
|
||||||
|
should_clear_sidebar = true;
|
||||||
|
append_pending_output();
|
||||||
|
log_to_sidebar = true;
|
||||||
|
g_rec_mutex_unlock(&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(&console_output_lock);
|
||||||
|
append_pending_output();
|
||||||
|
log_to_sidebar = false;
|
||||||
|
g_rec_mutex_unlock(&console_output_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark) {
|
||||||
|
GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
|
||||||
GtkTextIter iter;
|
GtkTextIter iter;
|
||||||
GtkTextIter start;
|
|
||||||
|
|
||||||
gtk_text_buffer_get_end_iter(text_buf, &iter);
|
|
||||||
GtkTextMark *start_mark = gtk_text_buffer_create_mark(text_buf, NULL, &iter, TRUE);
|
|
||||||
gtk_text_buffer_insert(text_buf, &iter, g_strdup(log_data->string), -1);
|
|
||||||
gtk_text_buffer_get_iter_at_mark(text_buf, &start, start_mark);
|
|
||||||
|
|
||||||
if (attributes & GB_LOG_BOLD) {
|
gtk_text_buffer_get_end_iter(buffer, &iter);
|
||||||
gtk_text_buffer_apply_tag_by_name(text_buf, "bold", &start, &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 void append_pending_output(void) {
|
||||||
|
g_rec_mutex_lock(&console_output_lock);
|
||||||
|
|
||||||
|
if (should_clear_sidebar) {
|
||||||
|
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);
|
||||||
|
should_clear_sidebar = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes & GB_LOG_DASHED_UNDERLINE) {
|
if (gtk_text_buffer_get_char_count(pending_console_output) > 0) {
|
||||||
gtk_text_buffer_apply_tag_by_name(text_buf, "dashed_underline", &start, &iter);
|
GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, 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(pending_console_output, &start);
|
||||||
|
gtk_text_buffer_get_end_iter(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(pending_console_output, "", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes & GB_LOG_UNDERLINE) {
|
g_rec_mutex_unlock(&console_output_lock);
|
||||||
gtk_text_buffer_apply_tag_by_name(text_buf, "underline", &start, &iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free((gpointer)log_data->string);
|
|
||||||
g_free(log_data);
|
|
||||||
gtk_text_buffer_delete_mark(text_buf, start_mark);
|
|
||||||
g_mutex_unlock(&console_output_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void console_log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes) {
|
static void console_log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes) {
|
||||||
if (string != NULL && !g_str_equal("", string)) {
|
g_rec_mutex_lock(&console_output_lock);
|
||||||
LogData *log_data = g_malloc(sizeof(LogData));
|
|
||||||
log_data->gb = gb;
|
|
||||||
log_data->string = g_strdup(string);
|
|
||||||
log_data->attributes = attributes;
|
|
||||||
|
|
||||||
g_idle_add((GSourceFunc) on_console_log, log_data);
|
if (string != NULL && !g_str_equal("", string)) {
|
||||||
|
GtkTextIter iter;
|
||||||
|
GtkTextIter start;
|
||||||
|
|
||||||
|
// Append attributed text to "pending_console_output" GtkTextBuffer
|
||||||
|
gtk_text_buffer_get_end_iter(pending_console_output, &iter);
|
||||||
|
GtkTextMark *start_mark = gtk_text_buffer_create_mark(pending_console_output, NULL, &iter, TRUE);
|
||||||
|
gtk_text_buffer_insert(pending_console_output, &iter, g_strdup(string), -1);
|
||||||
|
gtk_text_buffer_get_iter_at_mark(pending_console_output, &start, start_mark);
|
||||||
|
|
||||||
|
if (attributes & GB_LOG_BOLD) {
|
||||||
|
gtk_text_buffer_apply_tag_by_name(pending_console_output, "bold", &start, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & GB_LOG_DASHED_UNDERLINE) {
|
||||||
|
gtk_text_buffer_apply_tag_by_name(pending_console_output, "dashed_underline", &start, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes & GB_LOG_UNDERLINE) {
|
||||||
|
gtk_text_buffer_apply_tag_by_name(pending_console_output, "underline", &start, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_text_buffer_delete_mark(pending_console_output, start_mark);
|
||||||
|
|
||||||
|
g_idle_add((GSourceFunc) append_pending_output, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_rec_mutex_unlock(&console_output_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a `GApplication`s `GMenuModel` by ID
|
// Returns a `GApplication`s `GMenuModel` by ID
|
||||||
@ -494,7 +593,7 @@ static void create_fallback_canvas(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create our application’s menu.
|
// Create our application’s menu.
|
||||||
//
|
//
|
||||||
// This function tries to stick to the desktop environment’s conventions.
|
// This function tries to stick to the desktop environment’s conventions.
|
||||||
// For the GNOME Shell it uses a hamburger menu, otherwise it either lets
|
// For the GNOME Shell it uses a hamburger menu, otherwise it either lets
|
||||||
// the desktop environment shell handle the menu if it signals support for it
|
// the desktop environment shell handle the menu if it signals support for it
|
||||||
@ -512,7 +611,7 @@ static void setup_menu(GApplication *app) {
|
|||||||
const gchar *xdg_current_desktop = g_getenv("XDG_CURRENT_DESKTOP");
|
const gchar *xdg_current_desktop = g_getenv("XDG_CURRENT_DESKTOP");
|
||||||
const gchar *gdm_session = g_getenv("GDMSESSION");
|
const gchar *gdm_session = g_getenv("GDMSESSION");
|
||||||
const gchar *desktop_session = g_getenv("DESKTOP_SESSION");
|
const gchar *desktop_session = g_getenv("DESKTOP_SESSION");
|
||||||
|
|
||||||
gchar *desktop = (gchar *)xdg_current_desktop;
|
gchar *desktop = (gchar *)xdg_current_desktop;
|
||||||
if (desktop == NULL || g_str_equal(desktop, "")) desktop = (gchar *)gdm_session;
|
if (desktop == NULL || g_str_equal(desktop, "")) desktop = (gchar *)gdm_session;
|
||||||
if (desktop == NULL || g_str_equal(desktop, "")) desktop = (gchar *)desktop_session;
|
if (desktop == NULL || g_str_equal(desktop, "")) desktop = (gchar *)desktop_session;
|
||||||
@ -764,7 +863,7 @@ static void activate(GApplication *app, gpointer gui_data_gptr) {
|
|||||||
g_signal_connect(memory_viewer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
g_signal_connect(memory_viewer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
||||||
g_signal_connect(console, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
g_signal_connect(console, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
||||||
g_signal_connect(printer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
g_signal_connect(printer, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
||||||
|
|
||||||
g_signal_connect(get_object("vram_viewer_tileset_canvas"), "draw", G_CALLBACK(on_draw_vram_viewer_tileset), NULL);
|
g_signal_connect(get_object("vram_viewer_tileset_canvas"), "draw", G_CALLBACK(on_draw_vram_viewer_tileset), NULL);
|
||||||
g_signal_connect(get_object("vram_viewer_tilemap_canvas"), "draw", G_CALLBACK(on_draw_vram_viewer_tilemap), NULL);
|
g_signal_connect(get_object("vram_viewer_tilemap_canvas"), "draw", G_CALLBACK(on_draw_vram_viewer_tilemap), NULL);
|
||||||
|
|
||||||
@ -798,6 +897,12 @@ static void activate(GApplication *app, gpointer gui_data_gptr) {
|
|||||||
|
|
||||||
GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, "console_screen");
|
GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, "console_screen");
|
||||||
GtkTextBuffer *text_buf = gtk_text_view_get_buffer(text_view);
|
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, "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, "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_buffer_create_tag(text_buf, "dashed_underline", "underline", PANGO_UNDERLINE_DOUBLE, "underline-set", TRUE, NULL);
|
||||||
@ -811,12 +916,16 @@ static void activate(GApplication *app, gpointer gui_data_gptr) {
|
|||||||
|
|
||||||
g_mutex_init(&debugger_input_mutex);
|
g_mutex_init(&debugger_input_mutex);
|
||||||
g_cond_init(&debugger_input_cond);
|
g_cond_init(&debugger_input_cond);
|
||||||
g_mutex_init(&console_output_lock);
|
g_rec_mutex_init(&console_output_lock);
|
||||||
|
|
||||||
if (!debugger_input_queue) {
|
if (!debugger_input_queue) {
|
||||||
debugger_input_queue = g_ptr_array_sized_new(4);
|
debugger_input_queue = g_ptr_array_sized_new(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pending_console_output) {
|
||||||
|
pending_console_output = gtk_text_buffer_new(gtk_text_buffer_get_tag_table(text_buf));
|
||||||
|
}
|
||||||
|
|
||||||
// Start the emulation thread
|
// Start the emulation thread
|
||||||
run(gui_data);
|
run(gui_data);
|
||||||
}
|
}
|
||||||
@ -861,7 +970,7 @@ static void open(GApplication *app, GFile **files, gint n_files, const gchar *hi
|
|||||||
|
|
||||||
// Tell our application to quit.
|
// Tell our application to quit.
|
||||||
// After this functions has been called the `shutdown` signal will be issued.
|
// After this functions has been called the `shutdown` signal will be issued.
|
||||||
//
|
//
|
||||||
// TODO: Make sure we have a way to quit our emulation loop before `shutdown` gets called
|
// TODO: Make sure we have a way to quit our emulation loop before `shutdown` gets called
|
||||||
static void quit(GApplication *app) {
|
static void quit(GApplication *app) {
|
||||||
// Tell our own main loop to quit.
|
// Tell our own main loop to quit.
|
||||||
@ -884,10 +993,10 @@ static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data) {
|
|||||||
case GDK_KEY_a: mask = BUTTON_MASK_LEFT; break;
|
case GDK_KEY_a: mask = BUTTON_MASK_LEFT; break;
|
||||||
case GDK_KEY_s: mask = BUTTON_MASK_DOWN; break;
|
case GDK_KEY_s: mask = BUTTON_MASK_DOWN; break;
|
||||||
case GDK_KEY_d: mask = BUTTON_MASK_RIGHT; break;
|
case GDK_KEY_d: mask = BUTTON_MASK_RIGHT; break;
|
||||||
|
|
||||||
case GDK_KEY_g: mask = BUTTON_MASK_SELECT; break;
|
case GDK_KEY_g: mask = BUTTON_MASK_SELECT; break;
|
||||||
case GDK_KEY_h: mask = BUTTON_MASK_START; break;
|
case GDK_KEY_h: mask = BUTTON_MASK_START; break;
|
||||||
|
|
||||||
case GDK_KEY_k: mask = BUTTON_MASK_B; break;
|
case GDK_KEY_k: mask = BUTTON_MASK_B; break;
|
||||||
case GDK_KEY_l: mask = BUTTON_MASK_A; break;
|
case GDK_KEY_l: mask = BUTTON_MASK_A; break;
|
||||||
|
|
||||||
@ -923,7 +1032,7 @@ static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data) {
|
|||||||
}
|
}
|
||||||
break; }
|
break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->type == GDK_KEY_PRESS) {
|
if (event->type == GDK_KEY_PRESS) {
|
||||||
pressed_buttons |= mask;
|
pressed_buttons |= mask;
|
||||||
}
|
}
|
||||||
@ -981,7 +1090,7 @@ static void activate_open_vram_viewer(GSimpleAction *action, GVariant *parameter
|
|||||||
static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
GtkFileChooserNative *native = gtk_file_chooser_native_new("Open File", GTK_WINDOW(main_window), GTK_FILE_CHOOSER_ACTION_OPEN, "_Open", "_Cancel");
|
GtkFileChooserNative *native = gtk_file_chooser_native_new("Open File", GTK_WINDOW(main_window), GTK_FILE_CHOOSER_ACTION_OPEN, "_Open", "_Cancel");
|
||||||
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
|
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
|
||||||
|
|
||||||
if (res == GTK_RESPONSE_ACCEPT) {
|
if (res == GTK_RESPONSE_ACCEPT) {
|
||||||
// TODO: Emit an event for our emulation loop
|
// TODO: Emit an event for our emulation loop
|
||||||
g_message("%s", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native)));
|
g_message("%s", gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native)));
|
||||||
@ -1015,6 +1124,18 @@ static void activate_reset(GSimpleAction *action, GVariant *parameter, gpointer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// app.clear_console GAction
|
||||||
|
// Clears the debugger console
|
||||||
|
static void activate_clear_console(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||||
|
g_rec_mutex_lock(&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(&console_output_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer user_data) {
|
static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer user_data) {
|
||||||
if (!GB_is_inited(&gb)) {
|
if (!GB_is_inited(&gb)) {
|
||||||
g_simple_action_set_state(action, value);
|
g_simple_action_set_state(action, value);
|
||||||
@ -1092,7 +1213,7 @@ static void gl_init(GtkWidget *w) {
|
|||||||
g_debug("GL Context: %p", gtk_gl_area_get_context(gl_area));
|
g_debug("GL Context: %p", gtk_gl_area_get_context(gl_area));
|
||||||
|
|
||||||
gtk_gl_area_make_current(gl_area);
|
gtk_gl_area_make_current(gl_area);
|
||||||
|
|
||||||
if (gtk_gl_area_get_error(gl_area) != NULL) {
|
if (gtk_gl_area_get_error(gl_area) != NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -1181,7 +1302,7 @@ static gboolean on_draw_vram_viewer_tileset(GtkWidget *widget, cairo_t *cr, gpoi
|
|||||||
height = gtk_widget_get_allocated_height(widget);
|
height = gtk_widget_get_allocated_height(widget);
|
||||||
|
|
||||||
gtk_render_background(context, cr, 0, 0, width, height);
|
gtk_render_background(context, cr, 0, 0, width, height);
|
||||||
|
|
||||||
cairo_surface_t *surface = cairo_image_surface_create_for_data(
|
cairo_surface_t *surface = cairo_image_surface_create_for_data(
|
||||||
(unsigned char *) tileset_buffer,
|
(unsigned char *) tileset_buffer,
|
||||||
CAIRO_FORMAT_RGB24,
|
CAIRO_FORMAT_RGB24,
|
||||||
@ -1405,7 +1526,7 @@ G_MODULE_EXPORT void on_boot_rom_location_changed(GtkWidget *w, gpointer user_da
|
|||||||
if (g_strcmp0(id, "other") == 0) {
|
if (g_strcmp0(id, "other") == 0) {
|
||||||
GtkFileChooserNative *native = gtk_file_chooser_native_new("Select Folder", preferences, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Select", "_Cancel");
|
GtkFileChooserNative *native = gtk_file_chooser_native_new("Select Folder", preferences, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "_Select", "_Cancel");
|
||||||
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
|
gint res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native));
|
||||||
|
|
||||||
if (res == GTK_RESPONSE_ACCEPT) {
|
if (res == GTK_RESPONSE_ACCEPT) {
|
||||||
config.boot_rom_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native));
|
config.boot_rom_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(native));
|
||||||
update_boot_rom_selector(builder);
|
update_boot_rom_selector(builder);
|
||||||
@ -1537,7 +1658,7 @@ static void render_texture(void *pixels, void *previous) {
|
|||||||
|
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
GB_frame_blending_mode_t mode = get_frame_blending_mode();
|
GB_frame_blending_mode_t mode = get_frame_blending_mode();
|
||||||
if (!previous) {
|
if (!previous) {
|
||||||
mode = GB_FRAME_BLENDING_MODE_DISABLED;
|
mode = GB_FRAME_BLENDING_MODE_DISABLED;
|
||||||
@ -1600,7 +1721,7 @@ static void update_window_geometry() {
|
|||||||
GdkGeometry hints;
|
GdkGeometry hints;
|
||||||
hints.min_width = GB_get_screen_width(&gb);
|
hints.min_width = GB_get_screen_width(&gb);
|
||||||
hints.min_height = GB_get_screen_height(&gb);
|
hints.min_height = GB_get_screen_height(&gb);
|
||||||
|
|
||||||
gtk_window_set_geometry_hints(
|
gtk_window_set_geometry_hints(
|
||||||
GTK_WINDOW(main_window),
|
GTK_WINDOW(main_window),
|
||||||
NULL,
|
NULL,
|
||||||
@ -1734,7 +1855,7 @@ static void on_vblank(gpointer data) {
|
|||||||
g_bytes_new(oamInfo[row].image, 128 * sizeof(uint32_t)),
|
g_bytes_new(oamInfo[row].image, 128 * sizeof(uint32_t)),
|
||||||
GDK_COLORSPACE_RGB, true, 8, 8, oamHeight, 8 * sizeof(uint32_t)
|
GDK_COLORSPACE_RGB, true, 8, 8, oamHeight, 8 * sizeof(uint32_t)
|
||||||
);
|
);
|
||||||
|
|
||||||
GdkPixbuf *dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, 8 * 2, oamHeight * 2);
|
GdkPixbuf *dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, 8 * 2, oamHeight * 2);
|
||||||
|
|
||||||
gdk_pixbuf_scale(pixbuf, dest,
|
gdk_pixbuf_scale(pixbuf, dest,
|
||||||
@ -2017,13 +2138,13 @@ static void load_boot_rom(GuiData *gui_data) {
|
|||||||
if (config.boot_rom_path != NULL && g_strcmp0(config.boot_rom_path, "other") != 0 && g_strcmp0(config.boot_rom_path, "auto") != 0) {
|
if (config.boot_rom_path != NULL && g_strcmp0(config.boot_rom_path, "other") != 0 && g_strcmp0(config.boot_rom_path, "auto") != 0) {
|
||||||
boot_rom_path = g_build_filename(config.boot_rom_path, boot_rom_name, NULL);
|
boot_rom_path = g_build_filename(config.boot_rom_path, boot_rom_name, NULL);
|
||||||
g_message("Trying to load boot ROM from %s", boot_rom_path);
|
g_message("Trying to load boot ROM from %s", boot_rom_path);
|
||||||
|
|
||||||
if (GB_load_boot_rom(&gb, boot_rom_path)) {
|
if (GB_load_boot_rom(&gb, boot_rom_path)) {
|
||||||
g_free(boot_rom_path);
|
g_free(boot_rom_path);
|
||||||
g_warning("Falling back to internal boot ROM");
|
g_warning("Falling back to internal boot ROM");
|
||||||
goto internal_boot_rom;
|
goto internal_boot_rom;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free(boot_rom_path);
|
g_free(boot_rom_path);
|
||||||
}
|
}
|
||||||
else { internal_boot_rom:
|
else { internal_boot_rom:
|
||||||
@ -2039,7 +2160,7 @@ static void load_boot_rom(GuiData *gui_data) {
|
|||||||
|
|
||||||
boot_rom_data = g_bytes_get_data(boot_rom_f, &boot_rom_size);
|
boot_rom_data = g_bytes_get_data(boot_rom_f, &boot_rom_size);
|
||||||
GB_load_boot_rom_from_buffer(&gb, boot_rom_data, boot_rom_size);
|
GB_load_boot_rom_from_buffer(&gb, boot_rom_data, boot_rom_size);
|
||||||
|
|
||||||
g_bytes_unref(boot_rom_f);
|
g_bytes_unref(boot_rom_f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,8 @@ static gboolean init_audio();
|
|||||||
static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample);
|
static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample);
|
||||||
static char *sync_console_input(GB_gameboy_t *gb);
|
static char *sync_console_input(GB_gameboy_t *gb);
|
||||||
static char *async_console_input(GB_gameboy_t *gb);
|
static char *async_console_input(GB_gameboy_t *gb);
|
||||||
|
static void update_debugger_sidebar(GB_gameboy_t *gb);
|
||||||
|
static void append_pending_output();
|
||||||
static void on_console_log(gpointer user_data_gptr);
|
static void on_console_log(gpointer user_data_gptr);
|
||||||
static void console_log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
|
static void console_log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
|
||||||
|
|
||||||
@ -107,6 +109,7 @@ static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer a
|
|||||||
static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app);
|
static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||||
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer app);
|
static void activate_quit(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||||
static void activate_reset(GSimpleAction *action, GVariant *parameter, gpointer app);
|
static void activate_reset(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||||
|
static void activate_clear_console(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||||
|
|
||||||
static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer user_data);
|
static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer user_data);
|
||||||
static void on_mute_changed(GSimpleAction *action, GVariant *value, gpointer user_data);
|
static void on_mute_changed(GSimpleAction *action, GVariant *value, gpointer user_data);
|
||||||
|
@ -140,27 +140,18 @@ Maximilian Mader https://github.com/max-m</property>
|
|||||||
<property name="max_content_width">600</property>
|
<property name="max_content_width">600</property>
|
||||||
<property name="max_content_height">376</property>
|
<property name="max_content_height">376</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkViewport">
|
<object class="GtkTextView" id="console_screen">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">True</property>
|
||||||
<child>
|
<property name="editable">False</property>
|
||||||
<object class="GtkTextView" id="console_screen">
|
<property name="wrap_mode">word</property>
|
||||||
<property name="visible">True</property>
|
<property name="left_margin">5</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="right_margin">5</property>
|
||||||
<property name="editable">False</property>
|
<property name="top_margin">5</property>
|
||||||
<property name="wrap_mode">word</property>
|
<property name="bottom_margin">5</property>
|
||||||
<property name="left_margin">5</property>
|
<property name="cursor_visible">False</property>
|
||||||
<property name="right_margin">5</property>
|
<property name="accepts_tab">False</property>
|
||||||
<property name="top_margin">5</property>
|
<property name="monospace">True</property>
|
||||||
<property name="bottom_margin">5</property>
|
|
||||||
<property name="cursor_visible">False</property>
|
|
||||||
<property name="accepts_tab">False</property>
|
|
||||||
<property name="monospace">True</property>
|
|
||||||
<style>
|
|
||||||
<class name="border-none"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<style>
|
<style>
|
||||||
<class name="border-none"/>
|
<class name="border-none"/>
|
||||||
</style>
|
</style>
|
||||||
@ -191,25 +182,16 @@ Maximilian Mader https://github.com/max-m</property>
|
|||||||
<property name="min_content_width">320</property>
|
<property name="min_content_width">320</property>
|
||||||
<property name="min_content_height">80</property>
|
<property name="min_content_height">80</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkViewport">
|
<object class="GtkTextView" id="console_sidebar_input">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">True</property>
|
||||||
<child>
|
<property name="wrap_mode">word</property>
|
||||||
<object class="GtkTextView" id="console_sidebar_input">
|
<property name="left_margin">5</property>
|
||||||
<property name="visible">True</property>
|
<property name="right_margin">5</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="top_margin">5</property>
|
||||||
<property name="wrap_mode">word</property>
|
<property name="bottom_margin">5</property>
|
||||||
<property name="left_margin">5</property>
|
<property name="accepts_tab">False</property>
|
||||||
<property name="right_margin">5</property>
|
<property name="monospace">True</property>
|
||||||
<property name="top_margin">5</property>
|
|
||||||
<property name="bottom_margin">5</property>
|
|
||||||
<property name="accepts_tab">False</property>
|
|
||||||
<property name="monospace">True</property>
|
|
||||||
<style>
|
|
||||||
<class name="border-none"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<style>
|
<style>
|
||||||
<class name="border-none"/>
|
<class name="border-none"/>
|
||||||
</style>
|
</style>
|
||||||
@ -232,26 +214,17 @@ Maximilian Mader https://github.com/max-m</property>
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="shadow_type">in</property>
|
<property name="shadow_type">in</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkViewport">
|
<object class="GtkTextView" id="console_sidebar_output">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">True</property>
|
||||||
<child>
|
<property name="editable">False</property>
|
||||||
<object class="GtkTextView" id="console_sidebar_output">
|
<property name="wrap_mode">word</property>
|
||||||
<property name="visible">True</property>
|
<property name="left_margin">5</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="right_margin">5</property>
|
||||||
<property name="editable">False</property>
|
<property name="top_margin">5</property>
|
||||||
<property name="wrap_mode">word</property>
|
<property name="bottom_margin">5</property>
|
||||||
<property name="left_margin">5</property>
|
<property name="accepts_tab">False</property>
|
||||||
<property name="right_margin">5</property>
|
<property name="monospace">True</property>
|
||||||
<property name="top_margin">5</property>
|
|
||||||
<property name="bottom_margin">5</property>
|
|
||||||
<property name="accepts_tab">False</property>
|
|
||||||
<property name="monospace">True</property>
|
|
||||||
<style>
|
|
||||||
<class name="border-none"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<style>
|
<style>
|
||||||
<class name="border-none"/>
|
<class name="border-none"/>
|
||||||
</style>
|
</style>
|
||||||
@ -656,23 +629,6 @@ Maximilian Mader https://github.com/max-m</property>
|
|||||||
<property name="position">3</property>
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkCheckButton" id="integer_scaling_toggle">
|
|
||||||
<property name="label" translatable="yes">Use Integer Scaling</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">False</property>
|
|
||||||
<property name="margin_top">5</property>
|
|
||||||
<property name="margin_bottom">10</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
|
||||||
<signal name="toggled" handler="on_use_integer_scaling_changed" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">4</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="aspect_ratio_toggle">
|
<object class="GtkCheckButton" id="aspect_ratio_toggle">
|
||||||
<property name="label" translatable="yes">Keep Aspect Ratio</property>
|
<property name="label" translatable="yes">Keep Aspect Ratio</property>
|
||||||
@ -690,6 +646,23 @@ Maximilian Mader https://github.com/max-m</property>
|
|||||||
<property name="position">4</property>
|
<property name="position">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="integer_scaling_toggle">
|
||||||
|
<property name="label" translatable="yes">Use Integer Scaling</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
|
<property name="margin_bottom">10</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_use_integer_scaling_changed" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel" id="menubar_override_selector_label">
|
<object class="GtkLabel" id="menubar_override_selector_label">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
Loading…
Reference in New Issue
Block a user