#include "util.h" #include "config.h" #include // 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; } // Determines if a ComboBox entry should be converted into a separator. // Each element with a text value of `` will be converted into a separator element. gboolean is_separator(GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { gchar *text = NULL; gtk_tree_model_get(model, iter, 0, &text, -1); gboolean result = g_strcmp0("", text) == 0; g_free(text); return result; } // Recursively goes through all children of the given container and sets // our `is_separator` function to all children of type`GtkComboBox` void set_combo_box_row_separator_func(GtkContainer *container) { GList *children = gtk_container_get_children(container); for (GList *l = children; l; l = l->next) { if (GTK_IS_COMBO_BOX(l->data)) { gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(l->data), is_separator, NULL, NULL); } if (GTK_IS_CONTAINER(l->data)) { set_combo_box_row_separator_func(GTK_CONTAINER(l->data)); } } g_list_free(children); } gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark) { GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview); GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_iter_set_line_offset(&iter, 0); gtk_text_buffer_move_mark(buffer, mark, &iter); gtk_text_view_scroll_to_mark(textview, mark, 0.0, true, 0.0, 0.10); gtk_text_buffer_delete_mark(buffer, mark); return true; } gchar* format_scale_value_pct(GtkScale *scale, gdouble value) { GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(scale)); gdouble lower = gtk_adjustment_get_lower(adj); gdouble upper = gtk_adjustment_get_upper(adj); gdouble range = fabs(upper - lower); gdouble pct = ((value + fabs(lower)) / range) * 100.0; return g_strdup_printf ("%.0f%% ", pct); } gchar* format_scale_color_temperature(GtkScale *scale, gdouble value) { GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(scale)); gdouble lower = gtk_adjustment_get_lower(adj); gdouble upper = gtk_adjustment_get_upper(adj); gdouble range = fabs(upper - lower); gdouble normalized = (value + lower) / range; gdouble kelvin = 12000 + normalized * (12000 - 1000); return g_strdup_printf ("%.0fK ", kelvin); }