From 88cbe85fe2302054bc945090e398cf60f8d62362 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 31 Jul 2025 08:57:59 -0700
Subject: [PATCH] Added missing files
---
src/core/unix/SDL_gtk.c | 229 ++++++++++++++++++++++++++++++++++++++++
src/core/unix/SDL_gtk.h | 123 +++++++++++++++++++++
2 files changed, 352 insertions(+)
create mode 100644 src/core/unix/SDL_gtk.c
create mode 100644 src/core/unix/SDL_gtk.h
diff --git a/src/core/unix/SDL_gtk.c b/src/core/unix/SDL_gtk.c
new file mode 100644
index 0000000000000..f5f62ce9350ae
--- /dev/null
+++ b/src/core/unix/SDL_gtk.c
@@ -0,0 +1,229 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+#include "SDL_gtk.h"
+
+#define SDL_GTK_SYM2_OPTIONAL(ctx, lib, sub, fn, sym) \
+ ctx.sub.fn = (void *)SDL_LoadFunction(lib, #sym)
+
+#define SDL_GTK_SYM2(ctx, lib, sub, fn, sym) \
+ if (!(ctx.sub.fn = (void *)SDL_LoadFunction(lib, #sym))) { \
+ return SDL_SetError("Could not load GTK functions"); \
+ }
+
+#define SDL_GTK_SYM_OPTIONAL(ctx, lib, sub, fn) \
+ SDL_GTK_SYM2_OPTIONAL(ctx, lib, sub, fn, sub##_##fn)
+
+#define SDL_GTK_SYM(ctx, lib, sub, fn) \
+ SDL_GTK_SYM2(ctx, lib, sub, fn, sub##_##fn)
+
+// we never link directly to gtk
+static const char *gdk_names[] = {
+#ifdef SDL_PLATFORM_OPENBSD
+ "libgdk-3.so",
+#else
+ "libgdk-3.so.0",
+#endif
+ NULL
+};
+
+static const char *gtk_names[] = {
+#ifdef SDL_PLATFORM_OPENBSD
+ "libgtk-3.so",
+#else
+ "libgtk-3.so.0",
+#endif
+ NULL
+};
+
+static void *libgdk = NULL;
+static void *libgtk = NULL;
+
+static SDL_GtkContext gtk;
+static GMainContext *sdl_main_context;
+
+gulong signal_connect(gpointer instance, const gchar *detailed_signal, void *c_handler, gpointer data)
+{
+ return gtk.g.signal_connect_data(instance, detailed_signal, SDL_G_CALLBACK(c_handler), data, NULL, (SDL_GConnectFlags)0);
+}
+
+static void QuitGtk(void)
+{
+ SDL_UnloadObject(libgdk);
+ SDL_UnloadObject(libgtk);
+
+ libgdk = NULL;
+ libgtk = NULL;
+}
+
+static void *FindLib(const char **names)
+{
+ const char **name_ptr = names;
+ void *handle = NULL;
+
+ do {
+ handle = SDL_LoadObject(*name_ptr);
+ } while (*++name_ptr && !handle);
+
+ return handle;
+}
+
+static bool IsGtkInit()
+{
+ return libgdk != NULL && libgtk != NULL;
+}
+
+static bool InitGtk(void)
+{
+ if (!SDL_GetHintBoolean("SDL_ENABLE_GTK", true)) {
+ return false;
+ }
+
+ if (IsGtkInit()) {
+ return true;
+ }
+
+ libgdk = FindLib(gdk_names);
+ libgtk = FindLib(gtk_names);
+
+ if (!libgdk || !libgtk) {
+ QuitGtk();
+ return SDL_SetError("Could not load GTK libraries");
+ }
+
+ SDL_GTK_SYM(gtk, libgtk, gtk, init_check);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_new);
+ SDL_GTK_SYM(gtk, libgtk, gtk, separator_menu_item_new);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_new_with_label);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_submenu);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_get_label);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_label);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_append);
+ SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_insert);
+ SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_new_with_label);
+ SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_get_active);
+ SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_set_active);
+ SDL_GTK_SYM(gtk, libgtk, gtk, widget_show);
+ SDL_GTK_SYM(gtk, libgtk, gtk, widget_destroy);
+ SDL_GTK_SYM(gtk, libgtk, gtk, widget_get_sensitive);
+ SDL_GTK_SYM(gtk, libgtk, gtk, widget_set_sensitive);
+ SDL_GTK_SYM(gtk, libgtk, gtk, settings_get_default);
+
+ SDL_GTK_SYM(gtk, libgdk, g, signal_connect_data);
+ SDL_GTK_SYM(gtk, libgdk, g, mkdtemp);
+ SDL_GTK_SYM(gtk, libgdk, g, object_ref);
+ SDL_GTK_SYM(gtk, libgdk, g, object_ref_sink);
+ SDL_GTK_SYM(gtk, libgdk, g, object_unref);
+ SDL_GTK_SYM(gtk, libgdk, g, object_get);
+ SDL_GTK_SYM(gtk, libgdk, g, signal_handler_disconnect);
+ SDL_GTK_SYM(gtk, libgdk, g, main_context_push_thread_default);
+ SDL_GTK_SYM(gtk, libgdk, g, main_context_pop_thread_default);
+ SDL_GTK_SYM(gtk, libgdk, g, main_context_new);
+ SDL_GTK_SYM(gtk, libgdk, g, main_context_acquire);
+ SDL_GTK_SYM(gtk, libgdk, g, main_context_iteration);
+
+ gtk.g.signal_connect = signal_connect;
+
+ if (gtk.gtk.init_check(0, NULL) == GTK_FALSE) {
+ QuitGtk();
+ return SDL_SetError("Could not init GTK");
+ }
+
+ sdl_main_context = gtk.g.main_context_new();
+ if (!sdl_main_context) {
+ QuitGtk();
+ return SDL_SetError("Could not create GTK context");
+ }
+
+ if (!gtk.g.main_context_acquire(sdl_main_context)) {
+ QuitGtk();
+ return SDL_SetError("Could not acquire GTK context");
+ }
+
+ return true;
+}
+
+static SDL_InitState gtk_init;
+
+bool SDL_Gtk_Init(void)
+{
+ static bool is_gtk_available = true;
+
+ if (!is_gtk_available) {
+ return false; // don't keep trying if this fails.
+ }
+
+ if (SDL_ShouldInit(>k_init)) {
+ if (InitGtk()) {
+ SDL_SetInitialized(>k_init, true);
+ } else {
+ is_gtk_available = false;
+ SDL_SetInitialized(>k_init, true);
+ SDL_Gtk_Quit();
+ }
+ }
+
+ return IsGtkInit();
+}
+
+void SDL_Gtk_Quit(void)
+{
+ if (!SDL_ShouldQuit(>k_init)) {
+ return;
+ }
+
+ QuitGtk();
+ SDL_zero(gtk);
+ sdl_main_context = NULL;
+
+ SDL_SetInitialized(>k_init, false);
+}
+
+SDL_GtkContext *SDL_Gtk_GetContext(void)
+{
+ return IsGtkInit() ? >k : NULL;
+}
+
+SDL_GtkContext *SDL_Gtk_EnterContext(void)
+{
+ SDL_Gtk_Init();
+
+ if (IsGtkInit()) {
+ gtk.g.main_context_push_thread_default(sdl_main_context);
+ return >k;
+ }
+
+ return NULL;
+}
+
+void SDL_Gtk_ExitContext(SDL_GtkContext *ctx)
+{
+ if (ctx) {
+ ctx->g.main_context_pop_thread_default(sdl_main_context);
+ }
+}
+
+void SDL_UpdateGtk(void)
+{
+ if (IsGtkInit()) {
+ gtk.g.main_context_iteration(sdl_main_context, GTK_FALSE);
+ }
+}
diff --git a/src/core/unix/SDL_gtk.h b/src/core/unix/SDL_gtk.h
new file mode 100644
index 0000000000000..e76720ddb61f8
--- /dev/null
+++ b/src/core/unix/SDL_gtk.h
@@ -0,0 +1,123 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_internal.h"
+
+#ifndef SDL_gtk_h_
+#define SDL_gtk_h_
+
+/* Glib 2.0 */
+
+typedef unsigned long gulong;
+typedef void *gpointer;
+typedef char gchar;
+typedef int gint;
+typedef unsigned int guint;
+typedef double gdouble;
+typedef gint gboolean;
+typedef void (*GCallback)(void);
+typedef struct _GClosure GClosure;
+typedef void (*GClosureNotify) (gpointer data, GClosure *closure);
+typedef gboolean (*GSourceFunc) (gpointer user_data);
+
+typedef struct _GParamSpec GParamSpec;
+typedef struct _GMainContext GMainContext;
+
+typedef enum SDL_GConnectFlags
+{
+ SDL_G_CONNECT_DEFAULT = 0,
+ SDL_G_CONNECT_AFTER = 1 << 0,
+ SDL_G_CONNECT_SWAPPED = 1 << 1
+} SDL_GConnectFlags;
+
+#define SDL_G_CALLBACK(f) ((GCallback) (f))
+#define SDL_G_TYPE_CIC(ip, gt, ct) ((ct*) ip)
+#define SDL_G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (SDL_G_TYPE_CIC ((instance), (g_type), c_type))
+
+#define GTK_FALSE 0
+#define GTK_TRUE 1
+
+
+/* GTK 3.0 */
+
+typedef struct _GtkMenu GtkMenu;
+typedef struct _GtkMenuItem GtkMenuItem;
+typedef struct _GtkMenuShell GtkMenuShell;
+typedef struct _GtkWidget GtkWidget;
+typedef struct _GtkCheckMenuItem GtkCheckMenuItem;
+typedef struct _GtkSettings GtkSettings;
+
+#define GTK_MENU_ITEM(obj) (SDL_G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_MENU_ITEM, GtkMenuItem))
+#define GTK_WIDGET(widget) (SDL_G_TYPE_CHECK_INSTANCE_CAST ((widget), GTK_TYPE_WIDGET, GtkWidget))
+#define GTK_CHECK_MENU_ITEM(obj) (SDL_G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CHECK_MENU_ITEM, GtkCheckMenuItem))
+#define GTK_MENU(obj) (SDL_G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_MENU, GtkMenu))
+
+
+typedef struct SDL_GtkContext
+{
+ /* Glib 2.0 */
+ struct
+ {
+ gulong (*signal_connect)(gpointer instance, const gchar *detailed_signal, void *c_handler, gpointer data);
+ gulong (*signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, SDL_GConnectFlags connect_flags);
+ void (*object_unref)(gpointer object);
+ gchar *(*mkdtemp)(gchar *template);
+ gpointer (*object_ref_sink)(gpointer object);
+ gpointer (*object_ref)(gpointer object);
+ void (*object_get)(gpointer object, const gchar *first_property_name, ...);
+ void (*signal_handler_disconnect)(gpointer instance, gulong handler_id);
+ void (*main_context_push_thread_default)(GMainContext *context);
+ void (*main_context_pop_thread_default)(GMainContext *context);
+ GMainContext *(*main_context_new)(void);
+ gboolean (*main_context_acquire)(GMainContext *context);
+ gboolean (*main_context_iteration)(GMainContext *context, gboolean may_block);
+ } g;
+
+ /* GTK 3.0 */
+ struct
+ {
+ gboolean (*init_check)(int *argc, char ***argv);
+ GtkWidget *(*menu_new)(void);
+ GtkWidget *(*separator_menu_item_new)(void);
+ GtkWidget *(*menu_item_new_with_label)(const gchar *label);
+ void (*menu_item_set_submenu)(GtkMenuItem *menu_item, GtkWidget *submenu);
+ GtkWidget *(*check_menu_item_new_with_label)(const gchar *label);
+ void (*check_menu_item_set_active)(GtkCheckMenuItem *check_menu_item, gboolean is_active);
+ void (*widget_set_sensitive)(GtkWidget *widget, gboolean sensitive);
+ void (*widget_show)(GtkWidget *widget);
+ void (*menu_shell_append)(GtkMenuShell *menu_shell, GtkWidget *child);
+ void (*menu_shell_insert)(GtkMenuShell *menu_shell, GtkWidget *child, gint position);
+ void (*widget_destroy)(GtkWidget *widget);
+ const gchar *(*menu_item_get_label)(GtkMenuItem *menu_item);
+ void (*menu_item_set_label)(GtkMenuItem *menu_item, const gchar *label);
+ gboolean (*check_menu_item_get_active)(GtkCheckMenuItem *check_menu_item);
+ gboolean (*widget_get_sensitive)(GtkWidget *widget);
+ GtkSettings *(*settings_get_default)(void);
+ } gtk;
+} SDL_GtkContext;
+
+extern bool SDL_Gtk_Init(void);
+extern void SDL_Gtk_Quit(void);
+extern SDL_GtkContext *SDL_Gtk_EnterContext(void);
+extern void SDL_Gtk_ExitContext(SDL_GtkContext *gtk);
+extern void SDL_UpdateGtk(void);
+
+#endif // SDL_gtk_h_