[GTK3] Move some functions into util.c
This commit is contained in:
parent
7dbd0e18f9
commit
accaedbdac
261
gtk3/main.c
261
gtk3/main.c
@ -1,7 +1,6 @@
|
|||||||
#define G_LOG_USE_STRUCTURED
|
#define G_LOG_USE_STRUCTURED
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <epoxy/gl.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -9,7 +8,9 @@
|
|||||||
|
|
||||||
#include <Core/gb.h>
|
#include <Core/gb.h>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "util.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "check_menu_radio_group.h"
|
#include "check_menu_radio_group.h"
|
||||||
|
|
||||||
@ -29,113 +30,12 @@
|
|||||||
#define BUTTON_MASK_LEFT 0x40
|
#define BUTTON_MASK_LEFT 0x40
|
||||||
#define BUTTON_MASK_RIGHT 0x80
|
#define BUTTON_MASK_RIGHT 0x80
|
||||||
|
|
||||||
#define tileset_buffer_length 256 * 192 * 4
|
|
||||||
#define tilemap_buffer_length 256 * 256 * 4
|
|
||||||
|
|
||||||
#define str(x) #x
|
#define str(x) #x
|
||||||
#define xstr(x) str(x)
|
#define xstr(x) str(x)
|
||||||
#define get_object(id) gtk_builder_get_object(gui_data.builder, id)
|
#define get_object(id) gtk_builder_get_object(gui_data.builder, id)
|
||||||
#define builder_get(type, id) type(get_object(id))
|
#define builder_get(type, id) type(get_object(id))
|
||||||
#define action_set_enabled(map, name, value) g_simple_action_set_enabled(G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(map), name)), value);
|
#define action_set_enabled(map, name, value) g_simple_action_set_enabled(G_SIMPLE_ACTION(g_action_map_lookup_action(G_ACTION_MAP(map), name)), value);
|
||||||
|
|
||||||
typedef struct{
|
|
||||||
int16_t x, y;
|
|
||||||
uint16_t w, h;
|
|
||||||
} Rect;
|
|
||||||
|
|
||||||
typedef struct GuiData {
|
|
||||||
struct CliOptionData {
|
|
||||||
gchar *config_path;
|
|
||||||
gchar *boot_rom_path;
|
|
||||||
gboolean fullscreen;
|
|
||||||
GB_model_t model;
|
|
||||||
gboolean force_software_renderer;
|
|
||||||
} cli_options;
|
|
||||||
|
|
||||||
GFile *file;
|
|
||||||
gint sample_rate;
|
|
||||||
GDateTime *config_modification_date;
|
|
||||||
|
|
||||||
char *battery_save_path;
|
|
||||||
char *cheats_save_path;
|
|
||||||
|
|
||||||
GB_model_t prev_model;
|
|
||||||
|
|
||||||
const GThread *main_thread;
|
|
||||||
volatile bool running;
|
|
||||||
volatile bool stopping;
|
|
||||||
volatile bool stopped;
|
|
||||||
|
|
||||||
// GTK pointers
|
|
||||||
GtkApplication *main_application;
|
|
||||||
GtkBuilder *builder;
|
|
||||||
GtkApplicationWindow *main_window;
|
|
||||||
GtkBox *main_window_container;
|
|
||||||
GtkGLArea *gl_area;
|
|
||||||
GtkDrawingArea *fallback_canvas;
|
|
||||||
GtkWindow *preferences;
|
|
||||||
GtkWindow *vram_viewer;
|
|
||||||
GtkWindow *memory_viewer;
|
|
||||||
GtkWindow *console;
|
|
||||||
GtkWindow *printer;
|
|
||||||
|
|
||||||
// Debugger state
|
|
||||||
GtkTextBuffer *pending_console_output;
|
|
||||||
gboolean in_sync_input;
|
|
||||||
gchar *last_console_input;
|
|
||||||
gboolean log_to_sidebar;
|
|
||||||
gboolean should_clear_sidebar;
|
|
||||||
GMutex debugger_input_mutex;
|
|
||||||
GCond debugger_input_cond;
|
|
||||||
GRecMutex console_output_lock;
|
|
||||||
GPtrArray *debugger_input_queue;
|
|
||||||
bool vram_viewer_visible;
|
|
||||||
bool vram_viewer_updating;
|
|
||||||
gchar *vram_viewer_active_tab;
|
|
||||||
gboolean vram_viewer_is_cgb;
|
|
||||||
uint8_t vram_viewer_palette_data[16][0x40];
|
|
||||||
GB_oam_info_t oam_info[40];
|
|
||||||
uint16_t oam_count;
|
|
||||||
uint8_t oam_height;
|
|
||||||
uint32_t tileset_buffer[tileset_buffer_length];
|
|
||||||
uint32_t tilemap_buffer[tilemap_buffer_length];
|
|
||||||
GMutex tileset_buffer_mutex;
|
|
||||||
GMutex tilemap_buffer_mutex;
|
|
||||||
Rect scroll_rect;
|
|
||||||
|
|
||||||
// Audio and video
|
|
||||||
bool audio_initialized;
|
|
||||||
uint32_t *image_buffers[3];
|
|
||||||
unsigned char current_buffer;
|
|
||||||
Rect viewport;
|
|
||||||
bool border_mode_changed;
|
|
||||||
bool is_fullscreen;
|
|
||||||
bool supports_gl;
|
|
||||||
shader_t shader;
|
|
||||||
unsigned last_screen_width;
|
|
||||||
unsigned last_screen_height;
|
|
||||||
|
|
||||||
// Fast forward / slow motion
|
|
||||||
bool underclock_down;
|
|
||||||
bool rewind_down;
|
|
||||||
bool do_rewind;
|
|
||||||
bool rewind_paused;
|
|
||||||
bool turbo_down;
|
|
||||||
double clock_mutliplier;
|
|
||||||
double analog_clock_multiplier;
|
|
||||||
bool analog_clock_multiplier_valid;
|
|
||||||
|
|
||||||
// Input
|
|
||||||
uint8_t pressed_buttons;
|
|
||||||
struct Controller_t {
|
|
||||||
SDL_GameController *controller;
|
|
||||||
SDL_Haptic *haptic;
|
|
||||||
bool ignore_rumble;
|
|
||||||
} *controllers;
|
|
||||||
unsigned controller_count;
|
|
||||||
struct Controller_t *last_used_controller; // Used for rumble
|
|
||||||
} GuiData;
|
|
||||||
|
|
||||||
// Initialize the GuiData
|
// Initialize the GuiData
|
||||||
static GuiData gui_data = {
|
static GuiData gui_data = {
|
||||||
.cli_options = {
|
.cli_options = {
|
||||||
@ -168,44 +68,9 @@ static GuiData gui_data = {
|
|||||||
.clock_mutliplier = 1.0,
|
.clock_mutliplier = 1.0,
|
||||||
.analog_clock_multiplier = 1.0,
|
.analog_clock_multiplier = 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
GB_gameboy_t gb;
|
GB_gameboy_t gb;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
INPUT_UP,
|
|
||||||
INPUT_DOWN,
|
|
||||||
INPUT_LEFT,
|
|
||||||
INPUT_RIGHT,
|
|
||||||
INPUT_A,
|
|
||||||
INPUT_B,
|
|
||||||
INPUT_START,
|
|
||||||
INPUT_SELECT,
|
|
||||||
|
|
||||||
INPUT_TURBO,
|
|
||||||
INPUT_REWIND,
|
|
||||||
INPUT_SLOWDOWN,
|
|
||||||
|
|
||||||
INPUT_FULLSCREEN,
|
|
||||||
} input_names_t;
|
|
||||||
|
|
||||||
static unsigned key_map[] = {
|
|
||||||
[INPUT_UP] = GDK_KEY_w,
|
|
||||||
[INPUT_LEFT] = GDK_KEY_a,
|
|
||||||
[INPUT_DOWN] = GDK_KEY_s,
|
|
||||||
[INPUT_RIGHT] = GDK_KEY_d,
|
|
||||||
|
|
||||||
[INPUT_A] = GDK_KEY_l,
|
|
||||||
[INPUT_B] = GDK_KEY_k,
|
|
||||||
|
|
||||||
[INPUT_START] = GDK_KEY_h,
|
|
||||||
[INPUT_SELECT] = GDK_KEY_g,
|
|
||||||
|
|
||||||
[INPUT_TURBO] = GDK_KEY_space,
|
|
||||||
[INPUT_REWIND] = GDK_KEY_Tab,
|
|
||||||
[INPUT_SLOWDOWN] = GDK_KEY_Shift_L,
|
|
||||||
|
|
||||||
[INPUT_FULLSCREEN] = GDK_KEY_F11,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Forward declarations of the actions
|
// Forward declarations of the actions
|
||||||
static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer app);
|
static void activate_open(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||||
static void activate_close(GSimpleAction *action, GVariant *parameter, gpointer app);
|
static void activate_close(GSimpleAction *action, GVariant *parameter, gpointer app);
|
||||||
@ -253,52 +118,6 @@ static const GActionEntry app_entries[] = {
|
|||||||
{ "toggle_mute", NULL, NULL, "false", on_mute_changed },
|
{ "toggle_mute", NULL, NULL, "false", on_mute_changed },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void replace_extension(const char *src, size_t length, char *dest, const char *ext) {
|
|
||||||
memcpy(dest, src, length);
|
|
||||||
dest[length] = 0;
|
|
||||||
|
|
||||||
/* Remove extension */
|
|
||||||
for (size_t i = length; i--;) {
|
|
||||||
if (dest[i] == '/') break;
|
|
||||||
if (dest[i] == '.') {
|
|
||||||
dest[i] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add new extension */
|
|
||||||
strcat(dest, ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double clamp_double(double min, double max, double value) {
|
|
||||||
if (value < min) return min;
|
|
||||||
if (value > max) return max;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double max_double(double a, double b) {
|
|
||||||
if (a > b) return a;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double min_double(double a, double b) {
|
|
||||||
if (a < b) return a;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t convert_color(uint16_t color) {
|
|
||||||
const uint8_t r = ((uint16_t)(color & 0x1F) * 255) / 31;
|
|
||||||
const uint8_t g = ((uint16_t)((color >> 5) & 0x1F) * 255) / 31;
|
|
||||||
const uint8_t b = ((uint16_t)((color >> 10) & 0x1F) * 255) / 31;
|
|
||||||
|
|
||||||
return (r << 16) | (g << 8) | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void palette_color_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data_ptr) {
|
static void palette_color_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data_ptr) {
|
||||||
const gchar *title = gtk_tree_view_column_get_title(col);
|
const gchar *title = gtk_tree_view_column_get_title(col);
|
||||||
const uint8_t color_index = g_ascii_strtoll(&title[6], NULL, 10);
|
const uint8_t color_index = g_ascii_strtoll(&title[6], NULL, 10);
|
||||||
@ -405,51 +224,6 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The main function for the OpenGL version check workaround
|
|
||||||
void gl_check_realize(GtkWidget *w, gpointer user_data_ptr) {
|
|
||||||
gboolean *result = (gboolean *) user_data_ptr;
|
|
||||||
|
|
||||||
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_warning("Failed to create context: %s", 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_debug("OpenGL version: %d", version);
|
|
||||||
|
|
||||||
*result = version >= 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround to figure out if we have proper OpenGL support.
|
|
||||||
// Otherwise the application would crash after our GtkGlArea is realized
|
|
||||||
// and the context it uses is a legacy OpenGL 1.4 context because
|
|
||||||
// GTK3 calls OpenGL 2.0+ functions on it.
|
|
||||||
gboolean test_gl_support(void) {
|
|
||||||
gboolean result = false;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean init_controllers(void) {
|
static gboolean init_controllers(void) {
|
||||||
SDL_version compiled;
|
SDL_version compiled;
|
||||||
SDL_version linked;
|
SDL_version linked;
|
||||||
@ -564,14 +338,6 @@ static gboolean init_audio(void) {
|
|||||||
return gui_data.audio_initialized = true;
|
return gui_data.audio_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GB_model_t config_get_model_type(void) {
|
|
||||||
if (gui_data.cli_options.model != -1) {
|
|
||||||
return gui_data.cli_options.model;
|
|
||||||
}
|
|
||||||
|
|
||||||
return config_get_model();
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
if (gui_data.turbo_down) {
|
if (gui_data.turbo_down) {
|
||||||
static unsigned skip = 0;
|
static unsigned skip = 0;
|
||||||
@ -806,19 +572,6 @@ static char *async_console_input(GB_gameboy_t *gb) {
|
|||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *menubar_to_menu(GtkMenuBar *menubar) {
|
|
||||||
GtkWidget *menu = gtk_menu_new();
|
|
||||||
g_autoptr(GList) iter = gtk_container_get_children(GTK_CONTAINER(menubar));
|
|
||||||
|
|
||||||
while (iter) {
|
|
||||||
GtkWidget *item = GTK_WIDGET(iter->data);
|
|
||||||
gtk_widget_reparent(item, menu);
|
|
||||||
iter = iter->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating these items in the UI defintion files was buggy in some desktop
|
// Creating these items in the UI defintion files was buggy in some desktop
|
||||||
// environments and the manual call of `g_signal_connect` was needed anyway
|
// environments and the manual call of `g_signal_connect` was needed anyway
|
||||||
// because the UI definition can’t define string arguments for signal handlers.
|
// because the UI definition can’t define string arguments for signal handlers.
|
||||||
@ -1460,7 +1213,7 @@ static void load_boot_rom(GB_gameboy_t *gb, GB_boot_rom_t type) {
|
|||||||
static void init(void) {
|
static void init(void) {
|
||||||
if (GB_is_inited(&gb)) return;
|
if (GB_is_inited(&gb)) return;
|
||||||
|
|
||||||
GB_init(&gb, config_get_model_type());
|
GB_init(&gb, config_get_model_type(&gui_data));
|
||||||
|
|
||||||
GB_set_vblank_callback(&gb, vblank);
|
GB_set_vblank_callback(&gb, vblank);
|
||||||
GB_set_pixels_output(&gb, get_current_buffer());
|
GB_set_pixels_output(&gb, get_current_buffer());
|
||||||
@ -1487,8 +1240,8 @@ static void init(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void reset(void) {
|
static void reset(void) {
|
||||||
g_debug("Reset: %d == %d", config_get_model_type(), gui_data.prev_model);
|
g_debug("Reset: %d == %d", config_get_model_type(&gui_data), gui_data.prev_model);
|
||||||
GB_model_t current_model = config_get_model_type();
|
GB_model_t current_model = config_get_model_type(&gui_data);
|
||||||
|
|
||||||
if (gui_data.prev_model == -1 || gui_data.prev_model == current_model) {
|
if (gui_data.prev_model == -1 || gui_data.prev_model == current_model) {
|
||||||
GB_reset(&gb);
|
GB_reset(&gb);
|
||||||
@ -1499,7 +1252,7 @@ static void reset(void) {
|
|||||||
|
|
||||||
GB_set_palette(&gb, config_get_monochrome_palette());
|
GB_set_palette(&gb, config_get_monochrome_palette());
|
||||||
|
|
||||||
gui_data.prev_model = config_get_model_type();
|
gui_data.prev_model = config_get_model_type(&gui_data);
|
||||||
|
|
||||||
// Check SGB -> non-SGB and non-SGB to SGB transitions
|
// Check SGB -> non-SGB and non-SGB to SGB transitions
|
||||||
if (GB_get_screen_width(&gb) != gui_data.last_screen_width || GB_get_screen_height(&gb) != gui_data.last_screen_height) {
|
if (GB_get_screen_width(&gb) != gui_data.last_screen_width || GB_get_screen_height(&gb) != gui_data.last_screen_height) {
|
||||||
|
144
gtk3/types.h
Normal file
144
gtk3/types.h
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#ifndef types_h
|
||||||
|
#define types_h
|
||||||
|
|
||||||
|
#include "SDL.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
|
#define tileset_buffer_length 256 * 192 * 4
|
||||||
|
#define tilemap_buffer_length 256 * 256 * 4
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
int16_t x, y;
|
||||||
|
uint16_t w, h;
|
||||||
|
} Rect;
|
||||||
|
|
||||||
|
typedef struct GuiData {
|
||||||
|
struct CliOptionData {
|
||||||
|
gchar *config_path;
|
||||||
|
gchar *boot_rom_path;
|
||||||
|
gboolean fullscreen;
|
||||||
|
GB_model_t model;
|
||||||
|
gboolean force_software_renderer;
|
||||||
|
} cli_options;
|
||||||
|
|
||||||
|
GFile *file;
|
||||||
|
gint sample_rate;
|
||||||
|
GDateTime *config_modification_date;
|
||||||
|
|
||||||
|
char *battery_save_path;
|
||||||
|
char *cheats_save_path;
|
||||||
|
|
||||||
|
GB_model_t prev_model;
|
||||||
|
|
||||||
|
const GThread *main_thread;
|
||||||
|
volatile bool running;
|
||||||
|
volatile bool stopping;
|
||||||
|
volatile bool stopped;
|
||||||
|
|
||||||
|
// GTK pointers
|
||||||
|
GtkApplication *main_application;
|
||||||
|
GtkBuilder *builder;
|
||||||
|
GtkApplicationWindow *main_window;
|
||||||
|
GtkBox *main_window_container;
|
||||||
|
GtkGLArea *gl_area;
|
||||||
|
GtkDrawingArea *fallback_canvas;
|
||||||
|
GtkWindow *preferences;
|
||||||
|
GtkWindow *vram_viewer;
|
||||||
|
GtkWindow *memory_viewer;
|
||||||
|
GtkWindow *console;
|
||||||
|
GtkWindow *printer;
|
||||||
|
|
||||||
|
// Debugger state
|
||||||
|
GtkTextBuffer *pending_console_output;
|
||||||
|
gboolean in_sync_input;
|
||||||
|
gchar *last_console_input;
|
||||||
|
gboolean log_to_sidebar;
|
||||||
|
gboolean should_clear_sidebar;
|
||||||
|
GMutex debugger_input_mutex;
|
||||||
|
GCond debugger_input_cond;
|
||||||
|
GRecMutex console_output_lock;
|
||||||
|
GPtrArray *debugger_input_queue;
|
||||||
|
bool vram_viewer_visible;
|
||||||
|
bool vram_viewer_updating;
|
||||||
|
gchar *vram_viewer_active_tab;
|
||||||
|
gboolean vram_viewer_is_cgb;
|
||||||
|
uint8_t vram_viewer_palette_data[16][0x40];
|
||||||
|
GB_oam_info_t oam_info[40];
|
||||||
|
uint16_t oam_count;
|
||||||
|
uint8_t oam_height;
|
||||||
|
uint32_t tileset_buffer[tileset_buffer_length];
|
||||||
|
uint32_t tilemap_buffer[tilemap_buffer_length];
|
||||||
|
GMutex tileset_buffer_mutex;
|
||||||
|
GMutex tilemap_buffer_mutex;
|
||||||
|
Rect scroll_rect;
|
||||||
|
|
||||||
|
// Audio and video
|
||||||
|
bool audio_initialized;
|
||||||
|
uint32_t *image_buffers[3];
|
||||||
|
unsigned char current_buffer;
|
||||||
|
Rect viewport;
|
||||||
|
bool border_mode_changed;
|
||||||
|
bool is_fullscreen;
|
||||||
|
bool supports_gl;
|
||||||
|
shader_t shader;
|
||||||
|
unsigned last_screen_width;
|
||||||
|
unsigned last_screen_height;
|
||||||
|
|
||||||
|
// Fast forward / slow motion
|
||||||
|
bool underclock_down;
|
||||||
|
bool rewind_down;
|
||||||
|
bool do_rewind;
|
||||||
|
bool rewind_paused;
|
||||||
|
bool turbo_down;
|
||||||
|
double clock_mutliplier;
|
||||||
|
double analog_clock_multiplier;
|
||||||
|
bool analog_clock_multiplier_valid;
|
||||||
|
|
||||||
|
// Input
|
||||||
|
uint8_t pressed_buttons;
|
||||||
|
struct Controller_t {
|
||||||
|
SDL_GameController *controller;
|
||||||
|
SDL_Haptic *haptic;
|
||||||
|
bool ignore_rumble;
|
||||||
|
} *controllers;
|
||||||
|
unsigned controller_count;
|
||||||
|
struct Controller_t *last_used_controller; // Used for rumble
|
||||||
|
} GuiData;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
INPUT_UP,
|
||||||
|
INPUT_DOWN,
|
||||||
|
INPUT_LEFT,
|
||||||
|
INPUT_RIGHT,
|
||||||
|
INPUT_A,
|
||||||
|
INPUT_B,
|
||||||
|
INPUT_START,
|
||||||
|
INPUT_SELECT,
|
||||||
|
|
||||||
|
INPUT_TURBO,
|
||||||
|
INPUT_REWIND,
|
||||||
|
INPUT_SLOWDOWN,
|
||||||
|
|
||||||
|
INPUT_FULLSCREEN,
|
||||||
|
} input_names_t;
|
||||||
|
|
||||||
|
static unsigned key_map[] = {
|
||||||
|
[INPUT_UP] = GDK_KEY_w,
|
||||||
|
[INPUT_LEFT] = GDK_KEY_a,
|
||||||
|
[INPUT_DOWN] = GDK_KEY_s,
|
||||||
|
[INPUT_RIGHT] = GDK_KEY_d,
|
||||||
|
|
||||||
|
[INPUT_A] = GDK_KEY_l,
|
||||||
|
[INPUT_B] = GDK_KEY_k,
|
||||||
|
|
||||||
|
[INPUT_START] = GDK_KEY_h,
|
||||||
|
[INPUT_SELECT] = GDK_KEY_g,
|
||||||
|
|
||||||
|
[INPUT_TURBO] = GDK_KEY_space,
|
||||||
|
[INPUT_REWIND] = GDK_KEY_Tab,
|
||||||
|
[INPUT_SLOWDOWN] = GDK_KEY_Shift_L,
|
||||||
|
|
||||||
|
[INPUT_FULLSCREEN] = GDK_KEY_F11,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
114
gtk3/util.c
Normal file
114
gtk3/util.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "util.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include <epoxy/gl.h>
|
||||||
|
|
||||||
|
// Workaround to figure out if we have proper OpenGL support.
|
||||||
|
// Otherwise the application would crash after our GtkGlArea is realized
|
||||||
|
// and the context it uses is a legacy OpenGL 1.4 context because
|
||||||
|
// GTK3 calls OpenGL 2.0+ functions on it.
|
||||||
|
bool test_gl_support(void) {
|
||||||
|
gboolean result = false;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main function for the OpenGL version check workaround
|
||||||
|
void gl_check_realize(GtkWidget *w, gpointer user_data_ptr) {
|
||||||
|
gboolean *result = (gboolean *) user_data_ptr;
|
||||||
|
|
||||||
|
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_warning("Failed to create context: %s", 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_debug("OpenGL version: %d", version);
|
||||||
|
|
||||||
|
*result = version >= 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void replace_extension(const char *src, size_t length, char *dest, const char *ext) {
|
||||||
|
memcpy(dest, src, length);
|
||||||
|
dest[length] = 0;
|
||||||
|
|
||||||
|
/* Remove extension */
|
||||||
|
for (size_t i = length; i--;) {
|
||||||
|
if (dest[i] == '/') break;
|
||||||
|
if (dest[i] == '.') {
|
||||||
|
dest[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add new extension */
|
||||||
|
strcat(dest, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
double clamp_double(double min, double max, double value) {
|
||||||
|
if (value < min) return min;
|
||||||
|
if (value > max) return max;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double max_double(double a, double b) {
|
||||||
|
if (a > b) return a;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
double min_double(double a, double b) {
|
||||||
|
if (a < b) return a;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t convert_color(uint16_t color) {
|
||||||
|
const uint8_t r = ((uint16_t)(color & 0x1F) * 255) / 31;
|
||||||
|
const uint8_t g = ((uint16_t)((color >> 5) & 0x1F) * 255) / 31;
|
||||||
|
const uint8_t b = ((uint16_t)((color >> 10) & 0x1F) * 255) / 31;
|
||||||
|
|
||||||
|
return (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_model_t config_get_model_type(GuiData *gui_data) {
|
||||||
|
if (gui_data->cli_options.model != -1) {
|
||||||
|
return gui_data->cli_options.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config_get_model();
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *menubar_to_menu(GtkMenuBar *menubar) {
|
||||||
|
GtkWidget *menu = gtk_menu_new();
|
||||||
|
g_autoptr(GList) iter = gtk_container_get_children(GTK_CONTAINER(menubar));
|
||||||
|
|
||||||
|
while (iter) {
|
||||||
|
GtkWidget *item = GTK_WIDGET(iter->data);
|
||||||
|
gtk_widget_reparent(item, menu);
|
||||||
|
iter = iter->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
25
gtk3/util.h
Normal file
25
gtk3/util.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef util_h
|
||||||
|
#define util_h
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <Core/gb.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
bool test_gl_support(void);
|
||||||
|
void gl_check_realize(GtkWidget *w, gpointer user_data_ptr);
|
||||||
|
|
||||||
|
void replace_extension(const char *src, size_t length, char *dest, const char *ext);
|
||||||
|
|
||||||
|
double clamp_double(double min, double max, double value);
|
||||||
|
double max_double(double a, double b);
|
||||||
|
double min_double(double a, double b);
|
||||||
|
|
||||||
|
uint32_t convert_color(uint16_t color);
|
||||||
|
uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
|
||||||
|
GB_model_t config_get_model_type(GuiData *gui_data);
|
||||||
|
|
||||||
|
GtkWidget *menubar_to_menu(GtkMenuBar *menubar);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user