[GTK3] Somewhat working GtkDrawingArea fallback
This commit is contained in:
parent
a83d6eca5b
commit
8ce3b02833
348
gtk3/main.c
348
gtk3/main.c
@ -39,8 +39,10 @@ static void run(GApplication *app, UserData *user_data);
|
||||
static GtkApplication *main_application;
|
||||
static GtkBuilder *builder;
|
||||
static GtkGLArea *gl_area;
|
||||
static GtkDrawingArea *fallback_canvas;
|
||||
|
||||
static GtkApplicationWindow *main_window;
|
||||
static GtkBox *main_window_container;
|
||||
static GtkWindow *preferences;
|
||||
static GtkWindow *vram_viewer;
|
||||
static GtkWindow *memory_viewer;
|
||||
@ -54,6 +56,8 @@ static GB_gameboy_t gb;
|
||||
static uint32_t *image_buffers[3];
|
||||
static unsigned char current_buffer;
|
||||
|
||||
static bool supports_gl;
|
||||
|
||||
static bool paused = false;
|
||||
static bool underclock_down = false, rewind_down = false, do_rewind = false, rewind_paused = false, turbo_down = false;
|
||||
static double clock_mutliplier = 1.0;
|
||||
@ -69,7 +73,7 @@ static const size_t tilemap_buffer_length = 256 * 256 * 4;
|
||||
static uint32_t tilemap_buffer[tilemap_buffer_length] = {0};
|
||||
|
||||
static unsigned char number_of_buffers(void) {
|
||||
bool should_blend = true;
|
||||
bool should_blend = !fallback_canvas;
|
||||
|
||||
return should_blend? 3 : 2;
|
||||
}
|
||||
@ -122,7 +126,12 @@ static void vblank(GB_gameboy_t *gb) {
|
||||
GB_set_pixels_output(gb, get_pixels());
|
||||
|
||||
// Queue drawing of the current frame
|
||||
if (fallback_canvas) {
|
||||
gtk_widget_queue_draw(GTK_WIDGET(main_window));
|
||||
}
|
||||
else if (gl_area) {
|
||||
gtk_gl_area_queue_render(gl_area);
|
||||
}
|
||||
|
||||
if (vram_viewer_visible) {
|
||||
// TODO: Only update what is needed
|
||||
@ -135,8 +144,10 @@ static void vblank(GB_gameboy_t *gb) {
|
||||
}
|
||||
|
||||
static void update_viewport(void) {
|
||||
int win_width = gtk_widget_get_allocated_width(GTK_WIDGET(gl_area));
|
||||
int win_height = gtk_widget_get_allocated_height(GTK_WIDGET(gl_area));
|
||||
GtkWidget *w = fallback_canvas ? GTK_WIDGET(fallback_canvas) : GTK_WIDGET(gl_area);
|
||||
|
||||
int win_width = gtk_widget_get_allocated_width(w);
|
||||
int win_height = gtk_widget_get_allocated_height(w);
|
||||
|
||||
double x_factor = win_width / (double) GB_get_screen_width(&gb);
|
||||
double y_factor = win_height / (double) GB_get_screen_height(&gb);
|
||||
@ -165,7 +176,7 @@ static void update_viewport(void) {
|
||||
new_height
|
||||
};
|
||||
|
||||
glViewport(rect.x, rect.y, rect.w, rect.h);
|
||||
if (!fallback_canvas) glViewport(rect.x, rect.y, rect.w, rect.h);
|
||||
}
|
||||
|
||||
// Determines if a ComboBox entry should be converted into a separator.
|
||||
@ -199,22 +210,6 @@ static void set_combo_box_row_separator_func(GtkContainer *container) {
|
||||
g_list_free_full(list, NULL);
|
||||
}
|
||||
|
||||
// Returns true if the application should show a menubar
|
||||
static gboolean show_menubar(void) {
|
||||
switch (get_show_menubar()) {
|
||||
case MENUBAR_AUTO: {
|
||||
GtkSettings *settings = gtk_settings_get_default();
|
||||
gboolean result;
|
||||
|
||||
g_object_get(settings, "gtk-shell-shows-menubar", &result, NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
case MENUBAR_SHOW: return true;
|
||||
case MENUBAR_HIDE: return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -332,32 +327,86 @@ G_MODULE_EXPORT void on_show_window(GtkWidget *w, gpointer window) {
|
||||
gtk_widget_show_all(GTK_WIDGET(window));
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void gl_init() {
|
||||
const char *renderer;
|
||||
G_MODULE_EXPORT gboolean on_draw_fallback(GtkWidget *widget, cairo_t *cr, gpointer data) {
|
||||
GtkStyleContext *context = gtk_widget_get_style_context(widget);
|
||||
guint width = gtk_widget_get_allocated_width(widget);
|
||||
guint height = gtk_widget_get_allocated_height(widget);
|
||||
|
||||
gtk_gl_area_make_current(gl_area);
|
||||
if (gtk_gl_area_get_error(gl_area) != NULL) {
|
||||
return;
|
||||
guint screen_width = GB_get_screen_width(&gb);
|
||||
guint screen_height = GB_get_screen_height(&gb);
|
||||
|
||||
gtk_render_background(context, cr, 0, 0, width, height);
|
||||
|
||||
cairo_surface_t *surface = cairo_image_surface_create_for_data(
|
||||
(unsigned char *) get_current_buffer(),
|
||||
CAIRO_FORMAT_RGB24,
|
||||
screen_width,
|
||||
screen_height,
|
||||
cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, screen_width)
|
||||
);
|
||||
|
||||
cairo_translate(cr, rect.x, rect.y);
|
||||
cairo_scale(cr, rect.w / screen_width, rect.h / screen_height);
|
||||
cairo_set_source_surface(cr, surface, 0, 0);
|
||||
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
|
||||
cairo_paint(cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
renderer = (char *) glGetString(GL_RENDERER);
|
||||
g_print("GtkGLArea on %s\n", renderer ? renderer : "Unknown");
|
||||
|
||||
if (config.shader == NULL || !init_shader_with_name(&shader, config.shader)) {
|
||||
init_shader_with_name(&shader, "NearestNeighbor");
|
||||
}
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void gl_resize() {
|
||||
G_MODULE_EXPORT void resize() {
|
||||
update_viewport();
|
||||
}
|
||||
|
||||
static void create_fallback_canvas(void) {
|
||||
fallback_canvas = GTK_DRAWING_AREA(gtk_drawing_area_new());
|
||||
g_signal_connect(fallback_canvas, "draw", G_CALLBACK(on_draw_fallback), NULL);
|
||||
g_signal_connect(fallback_canvas, "size-allocate", G_CALLBACK(resize), NULL);
|
||||
gtk_box_pack_end(GTK_BOX(main_window_container), GTK_WIDGET(fallback_canvas), TRUE, TRUE, 0);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void gl_draw() {
|
||||
render_texture(get_current_buffer(), get_previous_buffer());
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void gl_finish() { }
|
||||
|
||||
G_MODULE_EXPORT void gl_init(GtkWidget *w) {
|
||||
GtkGLArea *gl_area = GTK_GL_AREA(w);
|
||||
|
||||
g_print("GL_INIT\n");
|
||||
const char *renderer;
|
||||
|
||||
g_print("GL Context: %p\n", gtk_gl_area_get_context(gl_area));
|
||||
|
||||
gtk_gl_area_make_current(gl_area);
|
||||
|
||||
if (gtk_gl_area_get_error(gl_area) != NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
renderer = (char *)glGetString(GL_RENDERER);
|
||||
g_print("GtkGLArea on %s\n", renderer ? renderer : "Unknown");
|
||||
|
||||
if (config.shader == NULL || !init_shader_with_name(&shader, config.shader) || !init_shader_with_name(&shader, "NearestNeighbor")) {
|
||||
GError *error = g_error_new_literal(g_quark_from_string("sameboy-gl-error"), 1, "Failed to initialize shaders");
|
||||
gtk_gl_area_set_error(gl_area, error);
|
||||
}
|
||||
else {
|
||||
g_signal_connect(gl_area, "render", G_CALLBACK(gl_draw), NULL);
|
||||
g_signal_connect(gl_area, "resize", G_CALLBACK(resize), NULL);
|
||||
g_signal_connect(gl_area, "unrealize", G_CALLBACK(gl_finish), NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
if (gtk_gl_area_get_error(gl_area) != NULL) {
|
||||
g_printerr("GtkGLArea: %s\n", gtk_gl_area_get_error(gl_area)->message);
|
||||
}
|
||||
|
||||
create_fallback_canvas();
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void on_vram_viewer_realize() {
|
||||
vram_viewer_visible = true;
|
||||
}
|
||||
@ -390,7 +439,7 @@ G_MODULE_EXPORT gboolean on_draw_vram_viewer_tileset(GtkWidget *widget, cairo_t
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT gboolean on_vram_viewer_tilemap(GtkWidget *widget, cairo_t *cr, gpointer data) {
|
||||
G_MODULE_EXPORT gboolean on_draw_vram_viewer_tilemap(GtkWidget *widget, cairo_t *cr, gpointer data) {
|
||||
guint width, height;
|
||||
GtkStyleContext *context;
|
||||
|
||||
@ -497,10 +546,133 @@ G_MODULE_EXPORT void on_color_menubar_override_changed(GtkWidget *w, gpointer us
|
||||
config.menubar_override = (gchar *)gtk_combo_box_get_active_id(GTK_COMBO_BOX(w));
|
||||
}
|
||||
|
||||
static void setup_menu(GApplication *app) {
|
||||
GMenuModel *menubar_model = get_menu_model(app, "menubar");
|
||||
enum menubar_type_t menubar_type = get_show_menubar();
|
||||
|
||||
// Try to use a sane default
|
||||
if (menubar_type == MENUBAR_AUTO) {
|
||||
GtkSettings *settings = gtk_settings_get_default();
|
||||
gboolean show_in_shell;
|
||||
g_object_get(settings, "gtk-shell-shows-menubar", &show_in_shell, NULL);
|
||||
|
||||
const gchar *xdg_current_desktop = g_getenv("XDG_CURRENT_DESKTOP");
|
||||
const gchar *gdm_session = g_getenv("GDMSESSION");
|
||||
const gchar *desktop_session = g_getenv("DESKTOP_SESSION");
|
||||
|
||||
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 *)desktop_session;
|
||||
|
||||
g_print("XDG_CURRENT_DESKTOP: %s\nGDMSESSION: %s\nDESKTOP_SESSION: %s\nChosen value: %s\nShow menu in shell: %d\n", xdg_current_desktop, gdm_session, desktop_session, desktop, show_in_shell);
|
||||
|
||||
if (desktop != NULL && show_in_shell) {
|
||||
menubar_type = MENUBAR_SHOW_IN_SHELL;
|
||||
}
|
||||
else if (desktop != NULL && g_str_match_string("GNOME", desktop, FALSE)) {
|
||||
if (g_str_match_string("GNOME-Flashback", desktop, FALSE) || g_str_match_string("GNOME-Classic", desktop, FALSE)) {
|
||||
menubar_type = MENUBAR_SHOW_IN_WINDOW;
|
||||
}
|
||||
else if (gdm_session != NULL && (g_str_match_string("gnome-classic", gdm_session, FALSE) || g_str_match_string("gnome-flashback", gdm_session, FALSE))) {
|
||||
menubar_type = MENUBAR_SHOW_IN_WINDOW;
|
||||
}
|
||||
else {
|
||||
menubar_type = MENUBAR_SHOW_HAMBURGER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
menubar_type = MENUBAR_SHOW_IN_WINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
switch (menubar_type) {
|
||||
case MENUBAR_AUTO:
|
||||
g_error("Unreachable\n");
|
||||
break;
|
||||
|
||||
case MENUBAR_SHOW_IN_SHELL:
|
||||
g_print("Showing menu in the shell\n");
|
||||
gtk_application_set_menubar(GTK_APPLICATION(app), menubar_model);
|
||||
break;
|
||||
|
||||
case MENUBAR_SHOW_IN_WINDOW: {
|
||||
g_print("Showing menu in the window\n");
|
||||
GtkMenuBar *menubar = GTK_MENU_BAR(gtk_menu_bar_new_from_model(menubar_model));
|
||||
gtk_box_pack_start(GTK_BOX(main_window_container), GTK_WIDGET(menubar), FALSE, FALSE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case MENUBAR_SHOW_HAMBURGER: {
|
||||
g_print("Showing hamburger\n");
|
||||
// Attach a custom title bar
|
||||
GtkWidget *titlebar = gtkget(GTK_WIDGET, "main_header_bar");
|
||||
gtk_window_set_titlebar(GTK_WINDOW(main_window), titlebar);
|
||||
|
||||
// Disable menubar
|
||||
gtk_application_set_menubar(GTK_APPLICATION(app), NULL);
|
||||
|
||||
// Hook menubar up to the hamburger button
|
||||
GtkMenuButton *hamburger_button = GTK_MENU_BUTTON(get_object("hamburger_button"));
|
||||
gtk_menu_button_set_menu_model(hamburger_button, menubar_model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void gl_check_realize(GtkWidget *w, gpointer user_data_gptr) {
|
||||
gboolean *result = (gboolean *) user_data_gptr;
|
||||
|
||||
GError *error = NULL;
|
||||
GdkWindow *gdk_window = gtk_widget_get_window(w);
|
||||
GdkGLContext *context = gdk_window_create_gl_context(gdk_window, &error);
|
||||
|
||||
if (error != NULL) {
|
||||
g_printerr("Failed to create context: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
*result = FALSE;
|
||||
}
|
||||
else {
|
||||
gdk_gl_context_make_current(context);
|
||||
int version = epoxy_gl_version();
|
||||
|
||||
g_object_run_dispose(G_OBJECT(context));
|
||||
g_object_unref(context);
|
||||
context = NULL;
|
||||
|
||||
gdk_gl_context_clear_current();
|
||||
|
||||
g_print("OpenGL version: %d\n", version);
|
||||
|
||||
*result = version >= 32;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean test_gl_support(void) {
|
||||
gboolean result = FALSE;
|
||||
|
||||
gtk_init(NULL, NULL);
|
||||
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
g_signal_connect(window, "realize", G_CALLBACK(gl_check_realize), &result);
|
||||
gtk_widget_realize(window);
|
||||
gtk_widget_destroy(window);
|
||||
window = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// This functions gets called immediately after registration of the GApplication
|
||||
static void startup(GApplication *app, gpointer user_data_gptr) {
|
||||
UserData *user_data = user_data_gptr;
|
||||
|
||||
// Very ugly workaround for GtkGlArea!
|
||||
// When a GtkGlArea is realized and it creates a legacy GL 1.4 context
|
||||
// it tries to use GL 2.0 functions to render the window which leads to the application crashing.
|
||||
// So we initialize GTK, create a dummy GtkWindow object, attach a `realize` callback and
|
||||
// in this callback create a GdkGLContext on this window. But instead of running the GTK main loop
|
||||
// we just realize and destroy the dummy window and compare the context’s version in the realize callback.
|
||||
supports_gl = test_gl_support();
|
||||
g_print("OpenGL supported: %s\n", supports_gl? "Yes" : "No");
|
||||
|
||||
builder = gtk_builder_new_from_resource(RESOURCE_PREFIX "ui/window.ui");
|
||||
gtk_builder_connect_signals(builder, NULL);
|
||||
|
||||
@ -529,65 +701,19 @@ static void startup(GApplication *app, gpointer user_data_gptr) {
|
||||
|
||||
// setup main window
|
||||
main_window = GTK_APPLICATION_WINDOW(gtk_application_window_new(GTK_APPLICATION(app)));
|
||||
gtk_application_window_set_show_menubar(main_window, false);
|
||||
main_window_container = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
|
||||
|
||||
// create our renderer area
|
||||
gl_area = GTK_GL_AREA(gtk_gl_area_new());
|
||||
gtk_gl_area_set_auto_render(gl_area, false);
|
||||
gtk_window_set_title(GTK_WINDOW(main_window), "SameBoy");
|
||||
gtk_application_window_set_show_menubar(main_window, false);
|
||||
gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(main_window_container));
|
||||
|
||||
setup_menu(app);
|
||||
|
||||
// Insert separators into `GtkComboBox`es
|
||||
set_combo_box_row_separator_func(GTK_CONTAINER(preferences));
|
||||
set_combo_box_row_separator_func(GTK_CONTAINER(vram_viewer));
|
||||
set_combo_box_row_separator_func(GTK_CONTAINER(memory_viewer));
|
||||
|
||||
// Connect signal handlers
|
||||
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_PRESS_MASK);
|
||||
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_RELEASE_MASK);
|
||||
g_signal_connect(main_window, "key_press_event", G_CALLBACK(on_key_press), NULL);
|
||||
g_signal_connect(main_window, "key_release_event", G_CALLBACK(on_key_press), NULL);
|
||||
|
||||
g_signal_connect(gl_area, "realize", G_CALLBACK(gl_init), NULL);
|
||||
g_signal_connect(gl_area, "render", G_CALLBACK(gl_draw), NULL);
|
||||
g_signal_connect(gl_area, "resize", G_CALLBACK(gl_resize), NULL);
|
||||
g_signal_connect(gl_area, "unrealize", G_CALLBACK(gl_finish), NULL);
|
||||
|
||||
g_signal_connect(vram_viewer, "realize", G_CALLBACK(on_vram_viewer_realize), NULL);
|
||||
g_signal_connect(vram_viewer, "unrealize", G_CALLBACK(on_vram_viewer_unrealize), NULL);
|
||||
|
||||
// Just hide our sub-windows when closing them
|
||||
g_signal_connect(preferences, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
||||
g_signal_connect(vram_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(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_tilemap_canvas"), "draw", G_CALLBACK(on_vram_viewer_tilemap), NULL);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(gl_area));
|
||||
|
||||
// Handle the whole menubar situation …
|
||||
GMenuModel *menubar = get_menu_model(app, "menubar");
|
||||
|
||||
if (show_menubar()) {
|
||||
// Show a classic menubar
|
||||
gtk_application_set_menubar(GTK_APPLICATION(app), menubar);
|
||||
}
|
||||
else {
|
||||
// Attach a custom title bar
|
||||
GtkWidget *titlebar = gtkget(GTK_WIDGET, "main_header_bar");
|
||||
gtk_window_set_titlebar(GTK_WINDOW(main_window), titlebar);
|
||||
|
||||
// Disable menubar
|
||||
gtk_application_set_menubar(GTK_APPLICATION(app), NULL);
|
||||
|
||||
// Hook menubar up to the hamburger button
|
||||
GtkMenuButton *hamburger_button = GTK_MENU_BUTTON(get_object("hamburger_button"));
|
||||
gtk_menu_button_set_menu_model(hamburger_button, menubar);
|
||||
}
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(main_window), "SameBoy");
|
||||
|
||||
// Define a set of window icons
|
||||
GList *icon_list = NULL;
|
||||
static char* icons[] = {
|
||||
@ -625,7 +751,41 @@ static void activate(GApplication *app, gpointer user_data_gptr) {
|
||||
gtk_window_fullscreen(GTK_WINDOW(main_window));
|
||||
}
|
||||
|
||||
// Connect signal handlers
|
||||
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_PRESS_MASK);
|
||||
gtk_widget_add_events(GTK_WIDGET(main_window), GDK_KEY_RELEASE_MASK);
|
||||
|
||||
g_signal_connect(main_window, "destroy", G_CALLBACK(on_quit), app);
|
||||
g_signal_connect(main_window, "key_press_event", G_CALLBACK(on_key_press), NULL);
|
||||
g_signal_connect(main_window, "key_release_event", G_CALLBACK(on_key_press), NULL);
|
||||
|
||||
g_signal_connect(vram_viewer, "realize", G_CALLBACK(on_vram_viewer_realize), NULL);
|
||||
g_signal_connect(vram_viewer, "unrealize", G_CALLBACK(on_vram_viewer_unrealize), NULL);
|
||||
|
||||
// Just hide our sub-windows when closing them
|
||||
g_signal_connect(preferences, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
|
||||
g_signal_connect(vram_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(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_tilemap_canvas"), "draw", G_CALLBACK(on_draw_vram_viewer_tilemap), NULL);
|
||||
|
||||
// create our renderer area
|
||||
if (supports_gl) {
|
||||
gl_area = GTK_GL_AREA(gtk_gl_area_new());
|
||||
gtk_gl_area_set_required_version(gl_area, 3, 2);
|
||||
gtk_gl_area_set_auto_render(gl_area, false);
|
||||
gtk_gl_area_set_has_alpha(gl_area, false);
|
||||
gtk_gl_area_set_has_depth_buffer(gl_area, false);
|
||||
gtk_gl_area_set_has_stencil_buffer(gl_area, false);
|
||||
g_signal_connect(gl_area, "realize", G_CALLBACK(gl_init), NULL);
|
||||
gtk_box_pack_end(GTK_BOX(main_window_container), GTK_WIDGET(gl_area), TRUE, TRUE, 0);
|
||||
}
|
||||
else {
|
||||
create_fallback_canvas();
|
||||
}
|
||||
|
||||
gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(main_window));
|
||||
gtk_widget_show_all(GTK_WIDGET(main_window));
|
||||
@ -741,6 +901,18 @@ static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) {
|
||||
return color;
|
||||
}
|
||||
|
||||
static uint32_t rgb_encode_fallback(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) {
|
||||
#ifdef GB_LITTLE_ENDIAN
|
||||
// ARGB
|
||||
uint32_t color = 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
#else
|
||||
// BGRA
|
||||
uint32_t color = (b << 24) | (g << 16) | (r << 8) | 0xFF;
|
||||
#endif
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static void update_window_geometry() {
|
||||
// Set size hints
|
||||
GdkGeometry hints;
|
||||
@ -793,7 +965,7 @@ static void run(GApplication *app, UserData *user_data) {
|
||||
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_pixels_output(&gb, get_current_buffer());
|
||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
GB_set_rgb_encode_callback(&gb, fallback_canvas? rgb_encode_fallback : rgb_encode);
|
||||
// GB_set_sample_rate(&gb, have_aspec.freq);
|
||||
GB_set_color_correction_mode(&gb, get_color_correction_mode());
|
||||
GB_set_highpass_filter_mode(&gb, get_highpass_mode());
|
||||
|
@ -190,17 +190,20 @@ void update_boot_rom_selector(GtkBuilder *builder) {
|
||||
gtk_combo_box_text_append(combo_box, "other", "Other");
|
||||
}
|
||||
|
||||
enum menubar_override get_show_menubar(void) {
|
||||
enum menubar_type_t get_show_menubar(void) {
|
||||
if (config.menubar_override == NULL) goto default_value;
|
||||
|
||||
if (g_strcmp0(config.menubar_override, "auto") == 0) {
|
||||
return MENUBAR_AUTO;
|
||||
}
|
||||
else if (g_strcmp0(config.menubar_override, "show") == 0) {
|
||||
return MENUBAR_SHOW;
|
||||
else if (g_strcmp0(config.menubar_override, "show_in_shell") == 0) {
|
||||
return MENUBAR_SHOW_IN_SHELL;
|
||||
}
|
||||
else if (g_strcmp0(config.menubar_override, "hide") == 0) {
|
||||
return MENUBAR_HIDE;
|
||||
else if (g_strcmp0(config.menubar_override, "show_in_window") == 0) {
|
||||
return MENUBAR_SHOW_IN_WINDOW;
|
||||
}
|
||||
else if (g_strcmp0(config.menubar_override, "show_hamburger") == 0) {
|
||||
return MENUBAR_SHOW_HAMBURGER;
|
||||
}
|
||||
|
||||
// This should not happen
|
||||
@ -208,16 +211,19 @@ enum menubar_override get_show_menubar(void) {
|
||||
default_value: return MENUBAR_AUTO;
|
||||
}
|
||||
|
||||
void set_show_menubar(enum menubar_override value) {
|
||||
void set_show_menubar(enum menubar_type_t value) {
|
||||
switch (value) {
|
||||
case MENUBAR_AUTO:
|
||||
config.menubar_override = "auto";
|
||||
break;
|
||||
case MENUBAR_SHOW:
|
||||
config.menubar_override = "show";
|
||||
case MENUBAR_SHOW_IN_SHELL:
|
||||
config.menubar_override = "show_in_shell";
|
||||
break;
|
||||
case MENUBAR_HIDE:
|
||||
config.menubar_override = "hide";
|
||||
case MENUBAR_SHOW_IN_WINDOW:
|
||||
config.menubar_override = "show_in_window";
|
||||
break;
|
||||
case MENUBAR_SHOW_HAMBURGER:
|
||||
config.menubar_override = "show_hamburger";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -58,10 +58,11 @@ typedef struct config_t {
|
||||
#undef EXPAND_GROUP_MEMBER
|
||||
} config_t;
|
||||
|
||||
enum menubar_override {
|
||||
enum menubar_type_t {
|
||||
MENUBAR_AUTO,
|
||||
MENUBAR_SHOW,
|
||||
MENUBAR_HIDE
|
||||
MENUBAR_SHOW_IN_SHELL,
|
||||
MENUBAR_SHOW_IN_WINDOW,
|
||||
MENUBAR_SHOW_HAMBURGER
|
||||
};
|
||||
|
||||
gchar* settings_file_path;
|
||||
@ -80,8 +81,8 @@ void free_settings(void);
|
||||
|
||||
void update_boot_rom_selector(GtkBuilder *builder);
|
||||
|
||||
enum menubar_override get_show_menubar(void);
|
||||
void set_show_menubar(enum menubar_override);
|
||||
enum menubar_type_t get_show_menubar(void);
|
||||
void set_show_menubar(enum menubar_type_t);
|
||||
|
||||
GB_color_correction_mode_t get_color_correction_mode(void);
|
||||
void set_color_correction_mode(GB_color_correction_mode_t);
|
||||
|
@ -63,11 +63,7 @@ static GLuint create_program(const char *vsh, const char *fsh)
|
||||
|
||||
bool init_shader_with_name(shader_t *shader, const char *name)
|
||||
{
|
||||
GLint major = 0, minor = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
|
||||
if (major * 0x100 + minor < 0x302) {
|
||||
if (epoxy_gl_version() < 32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@ typedef struct shader_s {
|
||||
GLuint texture;
|
||||
GLuint previous_texture;
|
||||
GLuint program;
|
||||
|
||||
bool compat_mode;
|
||||
} shader_t;
|
||||
|
||||
bool init_shader_with_name(shader_t *shader, const char *name);
|
||||
|
Loading…
Reference in New Issue
Block a user