SameBoy/gtk3/widgets/main_window.c

288 lines
10 KiB
C
Raw Normal View History

#include "main_window.h"
#include <Core/gb.h>
#include "gb_screen.h"
#include "main_menu.h"
#include "console_window.h"
#include "printer_window.h"
#include "preferences_window.h"
#include "vram_viewer_window.h"
struct _MainWindow {
GtkApplicationWindowClass parent_class;
// Child nodes
GtkBox *container;
GbScreen *screen;
bool force_software_renderer;
MainMenu *main_menu;
// The local SameBoy core instance
GB_gameboy_t *gb;
// Local sub-windows
ConsoleWindow *console;
GtkWindow *memory_viewer; // TODO
PrinterWindow *printer;
VramViewerWindow *vram_viewer;
};
G_DEFINE_TYPE(MainWindow, main_window, GTK_TYPE_APPLICATION_WINDOW);
typedef enum {
PROP_FORCE_SOFTWARE_RENDERER = 1,
N_PROPERTIES
} MainWindowProperty;
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
static void main_window_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
MainWindow *self = (MainWindow *) object;
switch ((MainWindowProperty) property_id) {
case PROP_FORCE_SOFTWARE_RENDERER: self->force_software_renderer = g_value_get_boolean(value); break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}
static void main_window_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
MainWindow *self = (MainWindow *) object;
switch ((MainWindowProperty) property_id) {
case PROP_FORCE_SOFTWARE_RENDERER: g_value_set_boolean(value, self->force_software_renderer); break;
default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}
static void on_update_color_correction(PreferencesWindow *pref, const GB_color_correction_mode_t mode, MainWindow *self) {
g_debug("on_update_color_correction(%d)", mode);
}
static void on_update_video_color_temperature(PreferencesWindow *pref, const gint light_temperature, MainWindow *self) {
g_debug("on_update_video_color_temperature(%d)", light_temperature);
if (GB_is_inited(self->gb)) {
// wouldnt it be nice to use the value set in the GtkAdjustment of the slider instead of 256.0 here?
GB_set_light_temperature(self->gb, (double) light_temperature / 256.0);
}
}
static void on_update_monochrome_palette(PreferencesWindow *pref, const GB_palette_t *palette, MainWindow *self) {
g_debug(
"on_update_monochrome_palette(\n\trgb(%d, %d, %d),\n\trgb(%d, %d, %d),\n\trgb(%d, %d, %d),\n\trgb(%d, %d, %d),\n\trgb(%d, %d, %d)\n)",
palette->colors[0].r, palette->colors[0].g, palette->colors[0].b,
palette->colors[1].r, palette->colors[1].g, palette->colors[1].b,
palette->colors[2].r, palette->colors[2].g, palette->colors[2].b,
palette->colors[3].r, palette->colors[3].g, palette->colors[3].b,
palette->colors[4].r, palette->colors[4].g, palette->colors[4].b
);
}
static void on_update_highpass(PreferencesWindow *pref, const GB_highpass_mode_t mode, MainWindow *self) {
g_debug("on_update_highpass(%d)", mode);
}
static void on_update_rewind_duration(PreferencesWindow *pref, const guint rewind_duration, MainWindow *self) {
g_debug("on_update_rewind_duration(%d)", rewind_duration);
}
static void on_update_rumble_mode(PreferencesWindow *pref, const GB_rumble_mode_t mode, MainWindow *self) {
g_debug("on_update_rumble_mode(%d)", mode);
}
static void on_update_video_display_border_mode(PreferencesWindow *pref, const gchar *name, MainWindow *self) {
g_debug("on_update_video_display_border_mode(%s)", name);
// gui_data.border_mode_changed = true;
}
static void on_update_video_shader(PreferencesWindow *pref, const gchar *name, MainWindow *self) {
g_debug("on_update_video_shader(%s)", name);
main_window_set_shader(self, name);
}
static void on_update_audio_sample_rate(PreferencesWindow *pref, const guint sample_rate, MainWindow *self) {
g_debug("on_update_audio_sample_rate(%d)", sample_rate);
if (sample_rate == -1) {
// gui_data.sample_rate = GB_audio_default_sample_rate();
}
else {
// gui_data.sample_rate = *sample_rate;
}
// init_audio();
}
static void on_update_audio_interference_volume(PreferencesWindow *pref, const guint *interference_volume, MainWindow *self) {
g_debug("on_update_audio_interference_volume(%d)", *interference_volume);
if (GB_is_inited(self->gb)) {
// wouldnt it be nice to use the value set in the GtkAdjustment of the slider instead of 100.0 here?
GB_set_interference_volume(self->gb, (double) *interference_volume / 100.0);
}
}
static void on_application_set(MainWindow *self, GObject *object) {
SameBoyApplication *app = SAMEBOY_APPLICATION(gtk_window_get_application(GTK_WINDOW(self)));
sameboy_application_preferences_signal_connect(app, "pref-update::color-correction", G_CALLBACK(on_update_color_correction), self);
sameboy_application_preferences_signal_connect(app, "pref-update::video-color-temperature", G_CALLBACK(on_update_video_color_temperature), self);
sameboy_application_preferences_signal_connect(app, "pref-update::monochrome-palette", G_CALLBACK(on_update_monochrome_palette), self);
sameboy_application_preferences_signal_connect(app, "pref-update::highpass", G_CALLBACK(on_update_highpass), self);
sameboy_application_preferences_signal_connect(app, "pref-update::rewind-duration", G_CALLBACK(on_update_rewind_duration), self);
sameboy_application_preferences_signal_connect(app, "pref-update::rumble-mode", G_CALLBACK(on_update_rumble_mode), self);
sameboy_application_preferences_signal_connect(app, "pref-update::video-display-border-mode", G_CALLBACK(on_update_video_display_border_mode), self);
sameboy_application_preferences_signal_connect(app, "pref-update::video-shader", G_CALLBACK(on_update_video_shader), self);
sameboy_application_preferences_signal_connect(app, "pref-update::audio-sample-rate", G_CALLBACK(on_update_audio_sample_rate), self);
sameboy_application_preferences_signal_connect(app, "pref-update::audio-interference-volume", G_CALLBACK(on_update_audio_interference_volume), self);
}
static void main_window_constructed(GObject *object) {
G_OBJECT_CLASS(main_window_parent_class)->constructed(object);
MainWindow *self = (MainWindow *) object;
self->screen = gb_screen_new(self->force_software_renderer);
gtk_box_pack_end(GTK_BOX(self->container), GTK_WIDGET(self->screen), true, true, 0);
g_signal_connect(self, "notify::application", G_CALLBACK(on_application_set), self);
}
static void main_window_init(MainWindow *self) {
gtk_widget_init_template(GTK_WIDGET(self));
gtk_window_set_title(GTK_WINDOW(self), "SameBoy");
gtk_application_window_set_show_menubar(GTK_APPLICATION_WINDOW(self), false);
// Connect signal handlers
gtk_widget_add_events(GTK_WIDGET(self), GDK_KEY_PRESS_MASK);
gtk_widget_add_events(GTK_WIDGET(self), GDK_KEY_RELEASE_MASK);
GtkAccelGroup *accelGroup = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(self), accelGroup);
gtk_widget_add_accelerator(GTK_WIDGET(self), "break-debugger-keyboard", accelGroup, GDK_KEY_C, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
self->gb = g_malloc(sizeof(GB_gameboy_t));
if (self->gb == NULL) {
g_warning("Out of memory!");
// TODO: Try to stop gracefully
exit(EXIT_FAILURE);
}
self->console = console_window_new(self->gb);
gtk_window_set_attached_to(GTK_WINDOW(self->console), GTK_WIDGET(self));
self->vram_viewer = vram_viewer_window_new();
gtk_window_set_attached_to(GTK_WINDOW(self->vram_viewer), GTK_WIDGET(self));
self->printer = printer_window_new();
gtk_window_set_attached_to(GTK_WINDOW(self->printer), GTK_WIDGET(self));
}
static void main_window_class_init(MainWindowClass *class) {
gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class), RESOURCE_PREFIX "ui/main_window.ui");
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), MainWindow, container);
gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), MainWindow, main_menu);
g_signal_new(
"break-debugger-keyboard", // signal name
G_TYPE_FROM_CLASS(class), // itype
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_ACTION, // signal_flags
0, // class_offset
NULL, // accumulator
NULL, // accumulator_data
NULL, // c_marshaller,
G_TYPE_NONE, // return_type
0 // n_params
);
obj_properties[PROP_FORCE_SOFTWARE_RENDERER] = g_param_spec_boolean(
"force_software_renderer", "Software Renderer", "Forces the use of software rendering via Cairo",
false,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE
);
G_OBJECT_CLASS(class)->set_property = main_window_set_property;
G_OBJECT_CLASS(class)->get_property = main_window_get_property;
G_OBJECT_CLASS(class)->constructed = main_window_constructed;
g_object_class_install_properties(G_OBJECT_CLASS(class), N_PROPERTIES, obj_properties);
}
MainWindow *main_window_new(SameBoyApplication *application, bool force_software_renderer) {
return g_object_new(
MAIN_WINDOW_TYPE,
"application", G_APPLICATION(application),
"force_software_renderer", force_software_renderer,
NULL
);
}
void main_window_fullscreen(MainWindow *self, bool make_fullscreen) {
if (make_fullscreen) {
gtk_window_fullscreen(GTK_WINDOW(self));
}
else {
gtk_window_unfullscreen(GTK_WINDOW(self));
}
}
void main_window_setup_menu(MainWindow *self, char *model_string) {
main_menu_setup(self->main_menu, model_string);
}
void main_window_open_console_window(MainWindow *self) {
gtk_widget_show_all(GTK_WIDGET(self->console));
}
void main_window_open_memory_viewer_window(MainWindow *self) {
g_warning("Not yet implemented!");
}
void main_window_open_vram_viewer_window(MainWindow *self) {
gtk_widget_show_all(GTK_WIDGET(self->vram_viewer));
}
void main_window_open_printer_window(MainWindow *self) {
gtk_widget_show_all(GTK_WIDGET(self->printer));
}
// GbScreen wrappers
void main_window_clear(MainWindow *self) {
return gb_screen_clear(self->screen);
}
uint32_t *main_window_get_pixels(MainWindow *self) {
return gb_screen_get_pixels(self->screen);
}
uint32_t *main_window_get_current_buffer(MainWindow *self) {
return gb_screen_get_current_buffer(self->screen);
}
uint32_t *main_window_get_previous_buffer(MainWindow *self) {
return gb_screen_get_previous_buffer(self->screen);
}
void main_window_flip(MainWindow *self) {
return gb_screen_flip(self->screen);
}
void main_window_set_resolution(MainWindow *self, unsigned width, unsigned height) {
return gb_screen_set_resolution(self->screen, width, height);
}
void main_window_set_blending_mode(MainWindow *self, GB_frame_blending_mode_t mode) {
return gb_screen_set_blending_mode(self->screen, mode);
}
void main_window_set_shader(MainWindow *self, const char *shader_name) {
return gb_screen_set_shader(self->screen, shader_name);
}
void main_window_queue_render(MainWindow *self) {
return gb_screen_queue_render(self->screen);
}