[GTK3] Implement basic debug console (no sidebar)
This commit is contained in:
parent
e1a1c3efbd
commit
10ac1bd0a5
137
gtk3/main.c
137
gtk3/main.c
@ -66,15 +66,21 @@ static uint8_t oamHeight;
|
||||
|
||||
static uint8_t pressed_buttons;
|
||||
|
||||
static GMutex debugger_input_mutex;
|
||||
static GCond debugger_input_cond;
|
||||
static GMutex console_output_lock;
|
||||
static GPtrArray *debugger_input_queue;
|
||||
|
||||
// List of GActions for the `app` prefix
|
||||
static const GActionEntry app_entries[] = {
|
||||
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||
{ "about", activate_about, NULL, NULL, NULL },
|
||||
{ "open", activate_open, NULL, NULL, NULL },
|
||||
{ "show_console", activate_show_console, NULL, NULL, NULL },
|
||||
{ "open_gtk_debugger", activate_open_gtk_debugger, NULL, NULL, NULL },
|
||||
{ "preferences", activate_preferences, NULL, NULL, NULL },
|
||||
{ "open_vram_viewer", activate_open_vram_viewer, NULL, NULL, NULL },
|
||||
{ "open_memory_viewer", activate_open_memory_viewer, NULL, NULL, NULL },
|
||||
{ "open_vram_viewer", activate_open_vram_viewer, NULL, NULL, NULL },
|
||||
{ "preferences", activate_preferences, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@ -320,6 +326,91 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) {
|
||||
SDL_QueueAudio(device_id, sample, sizeof(*sample));
|
||||
}
|
||||
|
||||
static char *sync_console_input(GB_gameboy_t *gb) {
|
||||
g_mutex_lock(&debugger_input_mutex);
|
||||
g_cond_wait(&debugger_input_cond, &debugger_input_mutex);
|
||||
|
||||
gchar *input = NULL;
|
||||
const gchar *_input = g_ptr_array_index(debugger_input_queue, 0);
|
||||
input = g_strdup(_input);
|
||||
gpointer ptr = g_ptr_array_remove_index(debugger_input_queue, 0);
|
||||
if (ptr) g_free(ptr);
|
||||
|
||||
g_mutex_unlock(&debugger_input_mutex);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
static char *async_console_input(GB_gameboy_t *gb) {
|
||||
if (debugger_input_queue->len == 0) return NULL;
|
||||
|
||||
g_mutex_lock(&debugger_input_mutex);
|
||||
|
||||
gchar *input = NULL;
|
||||
const gchar *_input = g_ptr_array_index(debugger_input_queue, 0);
|
||||
if (_input) {
|
||||
input = g_strdup(_input);
|
||||
gpointer ptr = g_ptr_array_remove_index(debugger_input_queue, 0);
|
||||
if (ptr) g_free(ptr);
|
||||
}
|
||||
|
||||
g_mutex_unlock(&debugger_input_mutex);
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
typedef struct LogData {
|
||||
GB_gameboy_t *gb;
|
||||
const char *string;
|
||||
GB_log_attributes attributes;
|
||||
} LogData;
|
||||
|
||||
static void on_console_log(gpointer user_data_gptr) {
|
||||
LogData *log_data = (LogData *)user_data_gptr;
|
||||
GB_gameboy_t *gb = log_data->gb;
|
||||
GB_log_attributes attributes = log_data->attributes;
|
||||
|
||||
g_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);
|
||||
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_apply_tag_by_name(text_buf, "bold", &start, &iter);
|
||||
}
|
||||
|
||||
if (attributes & GB_LOG_DASHED_UNDERLINE) {
|
||||
gtk_text_buffer_apply_tag_by_name(text_buf, "dashed_underline", &start, &iter);
|
||||
}
|
||||
|
||||
if (attributes & GB_LOG_UNDERLINE) {
|
||||
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) {
|
||||
if (string != NULL && !g_str_equal("", string)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a `GApplication`s `GMenuModel` by ID
|
||||
// GApplication menus are loaded from `gtk/menus.ui`, `gtk/menus-traditional.ui` and `gtk/menus-common.ui`.
|
||||
static GMenuModel *get_menu_model(GApplication *app, const char *id) {
|
||||
@ -623,6 +714,12 @@ static void activate(GApplication *app, gpointer user_data_gptr) {
|
||||
gtk_css_provider_load_from_resource(provider, RESOURCE_PREFIX "css/main.css");
|
||||
gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
GtkTextView *text_view = builder_get(GTK_TEXT_VIEW, "console_screen");
|
||||
GtkTextBuffer *text_buf = gtk_text_view_get_buffer(text_view);
|
||||
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_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(main_window));
|
||||
gtk_widget_show_all(GTK_WIDGET(main_window));
|
||||
|
||||
@ -705,6 +802,18 @@ static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer
|
||||
gtk_widget_hide(GTK_WIDGET(dialog));
|
||||
}
|
||||
|
||||
// app.show_console GAction
|
||||
// Opens the console
|
||||
static void activate_show_console(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||
if (debugger_input_queue) {
|
||||
while (debugger_input_queue->len) {
|
||||
g_ptr_array_remove_index_fast(debugger_input_queue, debugger_input_queue->len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_show_all(builder_get(GTK_WIDGET, "console"));
|
||||
}
|
||||
|
||||
// app.open_gtk_debugger GAction
|
||||
// Opens the GTK debugger
|
||||
static void activate_open_gtk_debugger(GSimpleAction *action, GVariant *parameter, gpointer app) {
|
||||
@ -1151,6 +1260,18 @@ G_MODULE_EXPORT void on_use_integer_scaling_changed(GtkWidget *w, gpointer user_
|
||||
update_viewport();
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void console_on_enter(GtkWidget *w, gpointer user_data_gptr) {
|
||||
GtkEntry *input = GTK_ENTRY(w);
|
||||
const gchar *_text = gtk_entry_get_text(input);
|
||||
const gchar *text = g_strdup(_text);
|
||||
gtk_entry_set_text(input, "");
|
||||
|
||||
g_mutex_lock(&debugger_input_mutex);
|
||||
g_ptr_array_add(debugger_input_queue, (gpointer)text);
|
||||
g_cond_signal(&debugger_input_cond);
|
||||
g_mutex_unlock(&debugger_input_mutex);
|
||||
}
|
||||
|
||||
static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) {
|
||||
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
@ -1515,6 +1636,13 @@ static gpointer run(gpointer user_data_gptr) {
|
||||
GB_model_t prev_model = GB_get_model(&gb);
|
||||
GB_model_t model = user_data->model? user_data->model : GB_MODEL_CGB_E; // TODO: Model from config
|
||||
|
||||
if (!debugger_input_queue) {
|
||||
g_mutex_init(&debugger_input_mutex);
|
||||
g_cond_init(&debugger_input_cond);
|
||||
g_mutex_init(&console_output_lock);
|
||||
debugger_input_queue = g_ptr_array_sized_new(4);
|
||||
}
|
||||
|
||||
if (GB_is_inited(&gb)) {
|
||||
GB_switch_model_and_reset(&gb, model);
|
||||
|
||||
@ -1534,7 +1662,7 @@ static gpointer run(gpointer user_data_gptr) {
|
||||
GB_init(&gb, model);
|
||||
update_window_geometry();
|
||||
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_vblank_callback(&gb, vblank);
|
||||
GB_set_pixels_output(&gb, get_current_buffer());
|
||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
GB_set_sample_rate(&gb, DEFAULT_AUDIO_SAMPLE_RATE);
|
||||
@ -1543,6 +1671,9 @@ static gpointer run(gpointer user_data_gptr) {
|
||||
GB_set_rewind_length(&gb, config.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);
|
||||
}
|
||||
|
||||
GError *error;
|
||||
|
@ -72,6 +72,7 @@ static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data);
|
||||
|
||||
// App actions
|
||||
static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||
static void activate_show_console(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||
static void activate_open_gtk_debugger(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||
static void activate_open_memory_viewer(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||
static void activate_open_vram_viewer(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||
|
@ -7,4 +7,39 @@
|
||||
min-height: 11px;
|
||||
min-width: 12px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* dark theme for the console, based on GNOME Terminal colors */
|
||||
.debug-console,
|
||||
.debug-console entry,
|
||||
.debug-console scrolledwindow,
|
||||
.debug-console textview,
|
||||
.debug-console textview text {
|
||||
background: #2E3436;
|
||||
color: #D3D7CF;
|
||||
font-size: 12px;
|
||||
border-color: #3d4548;
|
||||
}
|
||||
|
||||
.debug-console entry {
|
||||
background: #252a2c;
|
||||
border: none; /* 1px solid #1d2022 */
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.debug-console .border-none {
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
border-right: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.debug-console .border-right {
|
||||
border-right: 1px solid #3d4548;
|
||||
}
|
||||
|
||||
.debug-console .border-bottom {
|
||||
border-bottom: 1px solid #3d4548;
|
||||
}
|
||||
|
||||
|
@ -115,6 +115,7 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="console">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Debug Console</property>
|
||||
<property name="default_width">920</property>
|
||||
<property name="default_height">400</property>
|
||||
<child type="titlebar">
|
||||
@ -143,17 +144,35 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<object class="GtkTextView" id="console_screen">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Placeholder</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="wrap_mode">word</property>
|
||||
<property name="left_margin">5</property>
|
||||
<property name="right_margin">5</property>
|
||||
<property name="top_margin">5</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>
|
||||
<class name="border-none"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="border-none"/>
|
||||
<class name="border-right"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
@ -164,25 +183,41 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="min_content_width">320</property>
|
||||
<property name="min_content_height">80</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<object class="GtkTextView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Placeholder</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="left_margin">5</property>
|
||||
<property name="right_margin">5</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>
|
||||
<class name="border-none"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="border-none"/>
|
||||
<class name="border-bottom"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@ -200,17 +235,32 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<object class="GtkTextView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Placeholder</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="left_margin">5</property>
|
||||
<property name="right_margin">5</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>
|
||||
<class name="border-none"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="border-none"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
@ -222,6 +272,10 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="border-none"/>
|
||||
<class name="border-bottom"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
@ -230,7 +284,7 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry">
|
||||
<object class="GtkEntry" id="console_input">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_left">3</property>
|
||||
@ -238,6 +292,7 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="margin_top">3</property>
|
||||
<property name="margin_bottom">3</property>
|
||||
<property name="placeholder_text" translatable="yes">Console input</property>
|
||||
<signal name="activate" handler="console_on_enter" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@ -247,6 +302,9 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="debug-console"/>
|
||||
</style>
|
||||
</object>
|
||||
<object class="GtkListStore" id="dmg_models">
|
||||
<columns>
|
||||
@ -595,23 +653,6 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</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>
|
||||
<object class="GtkCheckButton" id="aspect_ratio_toggle">
|
||||
<property name="label" translatable="yes">Keep Aspect Ratio</property>
|
||||
@ -629,6 +670,23 @@ Maximilian Mader https://github.com/max-m</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</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>
|
||||
<object class="GtkLabel" id="menubar_override_selector_label">
|
||||
<property name="can_focus">False</property>
|
||||
|
Loading…
Reference in New Issue
Block a user