SameBoy/gtk3/widgets/main_window.c

288 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}