1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
#include <gtk/gtk.h>
#include "allegro5/allegro.h"
#include "allegro5/allegro_native_dialog.h"
#include "allegro5/internal/aintern_native_dialog.h"
#include "allegro5/internal/aintern_native_dialog_cfg.h"
#include "gtk_dialog.h"
#include "allegro5/internal/aintern_vector.h"
ALLEGRO_DEBUG_CHANNEL("gtk")
/* GTK is not thread safe. We launch a single thread which runs the GTK main
* loop, and it is the only thread which calls into GTK. (g_timeout_add may be
* called from other threads without locking.)
*
* We used to attempt to use gdk_threads_enter/gdk_threads_leave but hit
* some problems with deadlocks so switched to this.
*/
// G_STATIC_MUTEX_INIT causes a warning about a missing initializer, so if we
// have version 2.32 or newer don't use it to avoid the warning.
#if GLIB_CHECK_VERSION(2, 32, 0)
#define NEWER_GLIB 1
#else
#define NEWER_GLIB 0
#endif
#if NEWER_GLIB
static GMutex nd_gtk_mutex;
static void nd_gtk_lock(void) { g_mutex_lock(&nd_gtk_mutex); }
static void nd_gtk_unlock(void) { g_mutex_unlock(&nd_gtk_mutex); }
#else
static GStaticMutex nd_gtk_mutex = G_STATIC_MUTEX_INIT;
static void nd_gtk_lock(void) { g_static_mutex_lock(&nd_gtk_mutex); }
static void nd_gtk_unlock(void) { g_static_mutex_unlock(&nd_gtk_mutex); }
#endif
static GThread *nd_gtk_thread = NULL;
static void *nd_gtk_thread_func(void *data)
{
GAsyncQueue *queue = data;
ALLEGRO_DEBUG("GLIB %d.%d.%d\n",
GLIB_MAJOR_VERSION,
GLIB_MINOR_VERSION,
GLIB_MICRO_VERSION);
g_async_queue_push(queue, ACK_OK);
gtk_main();
ALLEGRO_INFO("GTK stopped.\n");
return NULL;
}
bool _al_gtk_ensure_thread(void)
{
bool ok = true;
#if !NEWER_GLIB
if (!g_thread_supported())
g_thread_init(NULL);
#endif
/* al_init_native_dialog_addon() didn't always exist so GTK might not have
* been initialised. gtk_init_check knows if it's been initialised already
* so we can just call it again.
*/
{
int argc = 0;
char **argv = NULL;
if (!gtk_init_check(&argc, &argv)) {
ALLEGRO_ERROR("gtk_init_check failed\n");
return false;
}
}
nd_gtk_lock();
if (!nd_gtk_thread) {
GAsyncQueue *queue = g_async_queue_new();
#if NEWER_GLIB
nd_gtk_thread = g_thread_new("gtk thread", nd_gtk_thread_func, queue);
#else
bool joinable = FALSE;
nd_gtk_thread = g_thread_create(nd_gtk_thread_func, queue, joinable, NULL);
#endif
if (!nd_gtk_thread) {
ok = false;
}
else {
ok = (g_async_queue_pop(queue) == ACK_OK);
}
g_async_queue_unref(queue);
}
nd_gtk_unlock();
return ok;
}
/* [user thread] */
bool _al_gtk_init_args(void *ptr, size_t size)
{
ARGS_BASE *args = (ARGS_BASE *)ptr;
memset(args, 0, size);
args->mutex = al_create_mutex();
if (!args->mutex) {
return false;
}
args->cond = al_create_cond();
if (!args->cond) {
al_destroy_mutex(args->mutex);
return false;
}
args->done = false;
args->response = true;
return args;
}
/* [user thread] */
bool _al_gtk_wait_for_args(GSourceFunc func, void *data)
{
ARGS_BASE *args = (ARGS_BASE *) data;
bool response;
al_lock_mutex(args->mutex);
g_timeout_add(0, func, data);
while (args->done == false) {
al_wait_cond(args->cond, args->mutex);
}
al_unlock_mutex(args->mutex);
response = args->response;
al_destroy_mutex(args->mutex);
al_destroy_cond(args->cond);
return response;
}
/* [gtk thread] */
void *_al_gtk_lock_args(gpointer data)
{
ARGS_BASE *args = (ARGS_BASE *) data;
al_lock_mutex(args->mutex);
return args;
}
/* [gtk thread] */
gboolean _al_gtk_release_args(gpointer data)
{
ARGS_BASE *args = (ARGS_BASE *) data;
args->done = true;
al_signal_cond(args->cond);
al_unlock_mutex(args->mutex);
return FALSE;
}
/* vim: set sts=3 sw=3 et: */
|