Atlas - SDL_gtk.c
Home / ext / SDL / src / core / unix Lines: 1 | Size: 6994 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22#include "SDL_gtk.h" 23 24#include <dlfcn.h> 25 26#define SDL_GTK_SYM2_OPTIONAL(ctx, lib, sub, fn, sym) \ 27 ctx.sub.fn = (void *)SDL_LoadFunction(lib, #sym) 28 29#define SDL_GTK_SYM2(ctx, lib, sub, fn, sym) \ 30 SDL_GTK_SYM2_OPTIONAL(ctx, lib, sub, fn, sym); \ 31 if (!ctx.sub.fn) { \ 32 return SDL_SetError("Could not load GTK functions"); \ 33 } 34 35#define SDL_GTK_SYM_OPTIONAL(ctx, lib, sub, fn) \ 36 SDL_GTK_SYM2_OPTIONAL(ctx, lib, sub, fn, sub##_##fn) 37 38#define SDL_GTK_SYM(ctx, lib, sub, fn) \ 39 SDL_GTK_SYM2(ctx, lib, sub, fn, sub##_##fn) 40 41#ifdef SDL_PLATFORM_OPENBSD 42#define GDK3_LIB "libgdk-3.so" 43#else 44#define GDK3_LIB "libgdk-3.so.0" 45#endif 46 47#ifdef SDL_PLATFORM_OPENBSD 48#define GTK3_LIB "libgtk-3.so" 49#else 50#define GTK3_LIB "libgtk-3.so.0" 51#endif 52 53// we never link directly to gtk 54static void *libgdk = NULL; 55static void *libgtk = NULL; 56 57static SDL_GtkContext gtk; 58static GMainContext *sdl_main_context; 59 60static gulong signal_connect(gpointer instance, const gchar *detailed_signal, void *c_handler, gpointer data) 61{ 62 return gtk.g.signal_connect_data(instance, detailed_signal, SDL_G_CALLBACK(c_handler), data, NULL, (SDL_GConnectFlags)0); 63} 64 65static void QuitGtk(void) 66{ 67 if (sdl_main_context) { 68 gtk.g.main_context_unref(sdl_main_context); 69 sdl_main_context = NULL; 70 } 71 72 SDL_UnloadObject(libgdk); 73 SDL_UnloadObject(libgtk); 74 75 libgdk = NULL; 76 libgtk = NULL; 77} 78 79static bool IsGtkInit() 80{ 81 return libgdk != NULL && libgtk != NULL; 82} 83 84static bool InitGtk(void) 85{ 86 if (!SDL_GetHintBoolean("SDL_ENABLE_GTK", true)) { 87 return false; 88 } 89 90 if (IsGtkInit()) { 91 return true; 92 } 93 94 // GTK only allows a single version to be loaded into a process at a time, 95 // so if there is one already loaded ensure it is the version we use. 96 void *progress_get_type = dlsym(RTLD_DEFAULT, "gtk_progress_get_type"); 97 void *misc_get_type = dlsym(RTLD_DEFAULT, "gtk_misc_get_type"); 98 if (progress_get_type || misc_get_type) { 99 void *libgtk3 = dlopen(GTK3_LIB, RTLD_NOLOAD | RTLD_LAZY); 100 if (!libgtk3) { 101 QuitGtk(); 102 return SDL_SetError("Could not load GTK-3, another GTK version already present"); 103 } 104 105 dlclose(libgtk3); 106 } 107 108 libgdk = SDL_LoadObject(GDK3_LIB); 109 libgtk = SDL_LoadObject(GTK3_LIB); 110 111 if (!libgdk || !libgtk) { 112 QuitGtk(); 113 return SDL_SetError("Could not load GTK libraries"); 114 } 115 116 SDL_GTK_SYM(gtk, libgtk, gtk, init_check); 117 SDL_GTK_SYM(gtk, libgtk, gtk, menu_new); 118 SDL_GTK_SYM(gtk, libgtk, gtk, separator_menu_item_new); 119 SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_new_with_label); 120 SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_submenu); 121 SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_get_label); 122 SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_label); 123 SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_append); 124 SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_insert); 125 SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_new_with_label); 126 SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_get_active); 127 SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_set_active); 128 SDL_GTK_SYM(gtk, libgtk, gtk, widget_show); 129 SDL_GTK_SYM(gtk, libgtk, gtk, widget_destroy); 130 SDL_GTK_SYM(gtk, libgtk, gtk, widget_get_sensitive); 131 SDL_GTK_SYM(gtk, libgtk, gtk, widget_set_sensitive); 132 SDL_GTK_SYM(gtk, libgtk, gtk, settings_get_default); 133 134 SDL_GTK_SYM(gtk, libgdk, g, signal_connect_data); 135 SDL_GTK_SYM(gtk, libgdk, g, mkdtemp); 136 SDL_GTK_SYM(gtk, libgdk, g, get_user_cache_dir); 137 SDL_GTK_SYM(gtk, libgdk, g, object_ref); 138 SDL_GTK_SYM(gtk, libgdk, g, object_ref_sink); 139 SDL_GTK_SYM(gtk, libgdk, g, object_unref); 140 SDL_GTK_SYM(gtk, libgdk, g, object_get); 141 SDL_GTK_SYM(gtk, libgdk, g, signal_handler_disconnect); 142 SDL_GTK_SYM(gtk, libgdk, g, main_context_push_thread_default); 143 SDL_GTK_SYM(gtk, libgdk, g, main_context_pop_thread_default); 144 SDL_GTK_SYM(gtk, libgdk, g, main_context_new); 145 SDL_GTK_SYM(gtk, libgdk, g, main_context_unref); 146 SDL_GTK_SYM(gtk, libgdk, g, main_context_acquire); 147 SDL_GTK_SYM(gtk, libgdk, g, main_context_iteration); 148 149 gtk.g.signal_connect = signal_connect; 150 151 if (gtk.gtk.init_check(NULL, NULL) == GTK_FALSE) { 152 QuitGtk(); 153 return SDL_SetError("Could not init GTK"); 154 } 155 156 sdl_main_context = gtk.g.main_context_new(); 157 if (!sdl_main_context) { 158 QuitGtk(); 159 return SDL_SetError("Could not create GTK context"); 160 } 161 162 if (!gtk.g.main_context_acquire(sdl_main_context)) { 163 QuitGtk(); 164 return SDL_SetError("Could not acquire GTK context"); 165 } 166 167 return true; 168} 169 170static SDL_InitState gtk_init; 171 172bool SDL_Gtk_Init(void) 173{ 174 static bool is_gtk_available = true; 175 176 if (!is_gtk_available) { 177 return false; // don't keep trying if this fails. 178 } 179 180 if (SDL_ShouldInit(>k_init)) { 181 if (InitGtk()) { 182 SDL_SetInitialized(>k_init, true); 183 } else { 184 is_gtk_available = false; 185 SDL_SetInitialized(>k_init, true); 186 SDL_Gtk_Quit(); 187 } 188 } 189 190 return IsGtkInit(); 191} 192 193void SDL_Gtk_Quit(void) 194{ 195 if (!SDL_ShouldQuit(>k_init)) { 196 return; 197 } 198 199 QuitGtk(); 200 SDL_zero(gtk); 201 202 SDL_SetInitialized(>k_init, false); 203} 204 205SDL_GtkContext *SDL_Gtk_GetContext(void) 206{ 207 return IsGtkInit() ? >k : NULL; 208} 209 210SDL_GtkContext *SDL_Gtk_EnterContext(void) 211{ 212 SDL_Gtk_Init(); 213 214 if (IsGtkInit()) { 215 gtk.g.main_context_push_thread_default(sdl_main_context); 216 return >k; 217 } 218 219 return NULL; 220} 221 222void SDL_Gtk_ExitContext(SDL_GtkContext *ctx) 223{ 224 if (ctx) { 225 ctx->g.main_context_pop_thread_default(sdl_main_context); 226 } 227} 228 229void SDL_UpdateGtk(void) 230{ 231 if (IsGtkInit()) { 232 gtk.g.main_context_iteration(sdl_main_context, GTK_FALSE); 233 gtk.g.main_context_iteration(NULL, GTK_FALSE); 234 } 235} 236[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.