/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Thread local storage.
 *
 *      By Trent Gamblin.
 *
 */

/* FIXME:
 *
 * There are several ways to get thread local storage:
 *
 * 1. pthreads.
 * 2. __thread keyword in gcc.
 * 3. __declspec(thread) in MSVC.
 * 4. TLS API under Windows.
 *
 * Since pthreads is available from the system everywhere except in
 * Windows, this is the only case which is problematic. It appears
 * that except for old mingw versions (before gcc 4.2) we can simply
 * use __thread, and for MSVC we can always use __declspec(thread):
 *
 * However there also is a WANT_TLS configuration variable which is on
 * by default and forces use of the TLS API instead. At the same time,
 * the implementation using the TLS API in this file does not work
 * with static linking. Someone should either completely remove
 * WANT_TLS, or fix the static linking case...
 */

#include <string.h>
#include "allegro5/allegro.h"
#include "allegro5/internal/aintern.h"
#include "allegro5/internal/aintern_bitmap.h"
#include "allegro5/internal/aintern_display.h"
#include "allegro5/internal/aintern_file.h"
#include "allegro5/internal/aintern_fshook.h"
#include "allegro5/internal/aintern_shader.h"
#include "allegro5/internal/aintern_tls.h"

#ifdef ALLEGRO_ANDROID
#include "allegro5/internal/aintern_android.h"
#endif

#if defined(ALLEGRO_MINGW32) && !defined(ALLEGRO_CFG_DLL_TLS)
   /*
    * MinGW < 4.2.1 doesn't have builtin thread local storage, so we
    * must use the Windows API.
    */
   #if __GNUC__ < 4
      #define ALLEGRO_CFG_DLL_TLS
   #elif __GNUC__ == 4 && __GNUC_MINOR__ < 2
      #define ALLEGRO_CFG_DLL_TLS
   #elif __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ < 1
      #define ALLEGRO_CFG_DLL_TLS
   #endif
#endif


/* Thread local storage for various per-thread state. */
typedef struct thread_local_state {
   /* New display parameters */
   int new_display_flags;
   int new_display_refresh_rate;
   int new_display_adapter;
   int new_window_x;
   int new_window_y;
   int new_bitmap_depth;
   int new_bitmap_samples;
   ALLEGRO_EXTRA_DISPLAY_SETTINGS new_display_settings;

   /* Current display */
   ALLEGRO_DISPLAY *current_display;

   /* Target bitmap */
   ALLEGRO_BITMAP *target_bitmap;

   /* Blender */
   ALLEGRO_BLENDER current_blender;

   /* Bitmap parameters */
   int new_bitmap_format;
   int new_bitmap_flags;
   int new_bitmap_wrap_u;
   int new_bitmap_wrap_v;

   /* Files */
   const ALLEGRO_FILE_INTERFACE *new_file_interface;
   const ALLEGRO_FS_INTERFACE *fs_interface;

   /* Error code */
   int allegro_errno;

   /* Title to use for a new window/display.
    * This is a static buffer for API reasons.
    */
   char new_window_title[ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE + 1];

#ifdef ALLEGRO_ANDROID
   JNIEnv *jnienv;
#endif

   /* Destructor ownership count */
   int dtor_owner_count;
} thread_local_state;


typedef struct INTERNAL_STATE {
   thread_local_state tls;
   ALLEGRO_BLENDER stored_blender;
   ALLEGRO_TRANSFORM stored_transform;
   ALLEGRO_TRANSFORM stored_projection_transform;
   int flags;
} INTERNAL_STATE;

ALLEGRO_STATIC_ASSERT(tls, sizeof(ALLEGRO_STATE) > sizeof(INTERNAL_STATE));


static void initialize_blender(ALLEGRO_BLENDER *b)
{
   b->blend_op = ALLEGRO_ADD;
   b->blend_source = ALLEGRO_ONE,
   b->blend_dest = ALLEGRO_INVERSE_ALPHA;
   b->blend_alpha_op = ALLEGRO_ADD;
   b->blend_alpha_source = ALLEGRO_ONE;
   b->blend_alpha_dest = ALLEGRO_INVERSE_ALPHA;
   b->blend_color = al_map_rgba_f(1.0f, 1.0f, 1.0f, 1.0f);
}


static void initialize_tls_values(thread_local_state *tls)
{
   memset(tls, 0, sizeof *tls);

   tls->new_display_adapter = ALLEGRO_DEFAULT_DISPLAY_ADAPTER;
   tls->new_window_x = INT_MAX;
   tls->new_window_y = INT_MAX;

   initialize_blender(&tls->current_blender);
   tls->new_bitmap_flags = ALLEGRO_CONVERT_BITMAP;
   tls->new_bitmap_format = ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA;
   tls->new_bitmap_wrap_u = ALLEGRO_BITMAP_WRAP_DEFAULT;
   tls->new_bitmap_wrap_v = ALLEGRO_BITMAP_WRAP_DEFAULT;
   tls->new_file_interface = &_al_file_interface_stdio;
   tls->fs_interface = &_al_fs_interface_stdio;
   memset(tls->new_window_title, 0, ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE + 1);

   _al_fill_display_settings(&tls->new_display_settings);
}

// FIXME: The TLS implementation below only works for dynamic linking
// right now - instead of using DllMain we should simply initialize
// on first request.
#ifdef ALLEGRO_STATICLINK
   #undef ALLEGRO_CFG_DLL_TLS
#endif

#if defined(ALLEGRO_CFG_DLL_TLS)
   #include "tls_dll.inc"
#elif defined(ALLEGRO_MACOSX) || defined(ALLEGRO_IPHONE) || defined(ALLEGRO_ANDROID) || defined(ALLEGRO_RASPBERRYPI)
   #include "tls_pthread.inc"
#else
   #include "tls_native.inc"
#endif



void _al_reinitialize_tls_values(void)
{
   thread_local_state *tls;
   if ((tls = tls_get()) == NULL)
      return;
   initialize_tls_values(tls);
}



void _al_set_new_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings)
{
   thread_local_state *tls;
   if ((tls = tls_get()) == NULL)
      return;
   memmove(&tls->new_display_settings, settings, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS));
}



ALLEGRO_EXTRA_DISPLAY_SETTINGS *_al_get_new_display_settings(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return 0;
   return &tls->new_display_settings;
}


/* Function: al_set_new_window_title
 */
void al_set_new_window_title(const char *title)
{
   thread_local_state *tls;
   size_t size;

   if ((tls = tls_get()) == NULL)
      return;

   size = strlen(title);

   if (size > ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE) {
      size = ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE;
   }

   _al_sane_strncpy(tls->new_window_title, title, size + 1);
}



/* Function: al_get_new_window_title
 */
const char *al_get_new_window_title(void)
{
   thread_local_state *tls;

   /* Return app name in case of error or if not set before. */
   if ((tls = tls_get()) == NULL)
      return al_get_app_name();

   if (strlen(tls->new_window_title) < 1)
      return al_get_app_name();


   return (const char *)tls->new_window_title;
}




/* Function: al_set_new_display_flags
 */
void al_set_new_display_flags(int flags)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->new_display_flags = flags;
}



/* Function: al_get_new_display_flags
 */
int al_get_new_display_flags(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return 0;
   return tls->new_display_flags;
}



/* Function: al_set_new_display_refresh_rate
 */
void al_set_new_display_refresh_rate(int refresh_rate)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->new_display_refresh_rate = refresh_rate;
}



/* Function: al_get_new_display_refresh_rate
 */
int al_get_new_display_refresh_rate(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return 0;
   return tls->new_display_refresh_rate;
}



/* Function: al_set_new_display_adapter
 */
void al_set_new_display_adapter(int adapter)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;

   if (adapter < 0) {
      tls->new_display_adapter = ALLEGRO_DEFAULT_DISPLAY_ADAPTER;
   }
   tls->new_display_adapter = adapter;
}



/* Function: al_get_new_display_adapter
 */
int al_get_new_display_adapter(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return ALLEGRO_DEFAULT_DISPLAY_ADAPTER;
   return tls->new_display_adapter;
}



/* Function: al_set_new_window_position
 */
void al_set_new_window_position(int x, int y)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->new_window_x = x;
   tls->new_window_y = y;
}


/* Function: al_get_new_window_position
 */
void al_get_new_window_position(int *x, int *y)
{
   thread_local_state *tls;
   int new_window_x = INT_MAX;
   int new_window_y = INT_MAX;

   if ((tls = tls_get()) != NULL) {
      new_window_x = tls->new_window_x;
      new_window_y = tls->new_window_y;
   }

   if (x)
      *x = new_window_x;
   if (y)
      *y = new_window_y;
}



/* Make the given display current, without changing the target bitmap.
 * This is used internally to change the current display transiently.
 */
bool _al_set_current_display_only(ALLEGRO_DISPLAY *display)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return false;

   if (tls->current_display &&
         tls->current_display->vt &&
         tls->current_display->vt->unset_current_display) {
      tls->current_display->vt->unset_current_display(tls->current_display);
      tls->current_display = NULL;
   }

   if (display &&
         display->vt &&
         display->vt->set_current_display) {
      if (!display->vt->set_current_display(display))
         return false;
   }

   tls->current_display = display;
   return true;
}



/* Function: al_get_current_display
 */
ALLEGRO_DISPLAY *al_get_current_display(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return NULL;
   return tls->current_display;
}



/* Function: al_set_target_bitmap
 */
void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)
{
   thread_local_state *tls;
   ALLEGRO_DISPLAY *old_display;
   ALLEGRO_DISPLAY *new_display;
   ALLEGRO_SHADER *old_shader;
   ALLEGRO_SHADER *new_shader;
   bool same_shader;
   int bitmap_flags = bitmap ? al_get_bitmap_flags(bitmap) : 0;

   ASSERT(!al_is_bitmap_drawing_held());

   if (bitmap) {
      if (bitmap->parent) {
         bitmap->parent->dirty = true;
      }
      else {
         bitmap->dirty = true;
      }
   }

   if ((tls = tls_get()) == NULL)
      return;

   old_display = tls->current_display;

   if (tls->target_bitmap)
      old_shader = tls->target_bitmap->shader;
   else
      old_shader = NULL;

   if (bitmap == NULL) {
      /* Explicitly releasing the current rendering context. */
      new_display = NULL;
      new_shader = NULL;
   }
   else if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) {
      /* Setting a memory bitmap doesn't change the rendering context. */
      new_display = old_display;
      new_shader = NULL;
   }
   else {
      new_display = _al_get_bitmap_display(bitmap);
      new_shader = bitmap->shader;
   }

   same_shader = (old_shader == new_shader && old_display == new_display);

   /* Unset the old shader if necessary. */
   if (old_shader && !same_shader) {
      old_shader->vt->unuse_shader(old_shader, old_display);
   }

   /* Change the rendering context if necessary. */
   if (old_display != new_display) {
      if (old_display &&
            old_display->vt &&
            old_display->vt->unset_current_display) {
         old_display->vt->unset_current_display(old_display);
      }

      tls->current_display = new_display;

      if (new_display &&
            new_display->vt &&
            new_display->vt->set_current_display) {
         new_display->vt->set_current_display(new_display);
      }
   }

   /* Change the target bitmap itself. */
   tls->target_bitmap = bitmap;

   if (bitmap &&
         !(bitmap_flags & ALLEGRO_MEMORY_BITMAP) &&
         new_display &&
         new_display->vt &&
         new_display->vt->set_target_bitmap)
   {
      new_display->vt->set_target_bitmap(new_display, bitmap);

      /* Set the new shader if necessary.  This should done before the
       * update_transformation call, which will also update the shader's
       * al_projview_matrix variable.
       */
      if (!same_shader || !new_shader) {
         al_use_shader(new_shader);
      }

      new_display->vt->update_transformation(new_display, bitmap);
   }
}



/* Function: al_set_target_backbuffer
 */
void al_set_target_backbuffer(ALLEGRO_DISPLAY *display)
{
   al_set_target_bitmap(al_get_backbuffer(display));
}



/* Function: al_get_target_bitmap
 */
ALLEGRO_BITMAP *al_get_target_bitmap(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return 0;
   return tls->target_bitmap;
}



/* Function: al_set_blender
 */
void al_set_blender(int op, int src, int dst)
{
   al_set_separate_blender(op, src, dst, op, src, dst);
}



/* Function: al_set_blend_color
*/
void al_set_blend_color(ALLEGRO_COLOR color)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;

   tls->current_blender.blend_color = color;
}


/* Function: al_set_separate_blender
 */
void al_set_separate_blender(int op, int src, int dst,
   int alpha_op, int alpha_src, int alpha_dst)
{
   thread_local_state *tls;
   ALLEGRO_BLENDER *b;

   ASSERT(op >= 0 && op < ALLEGRO_NUM_BLEND_OPERATIONS);
   ASSERT(src >= 0 && src < ALLEGRO_NUM_BLEND_MODES);
   ASSERT(dst >= 0 && src < ALLEGRO_NUM_BLEND_MODES);
   ASSERT(alpha_op >= 0 && alpha_op < ALLEGRO_NUM_BLEND_OPERATIONS);
   ASSERT(alpha_src >= 0 && alpha_src < ALLEGRO_NUM_BLEND_MODES);
   ASSERT(alpha_dst >= 0 && alpha_dst < ALLEGRO_NUM_BLEND_MODES);

   if ((tls = tls_get()) == NULL)
      return;

   b = &tls->current_blender;

   b->blend_op = op;
   b->blend_source = src;
   b->blend_dest = dst;
   b->blend_alpha_op = alpha_op;
   b->blend_alpha_source = alpha_src;
   b->blend_alpha_dest = alpha_dst;
}



/* Function: al_get_blender
 */
void al_get_blender(int *op, int *src, int *dst)
{
   al_get_separate_blender(op, src, dst, NULL, NULL, NULL);
}



/* Function: al_get_blend_color
*/
ALLEGRO_COLOR al_get_blend_color(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return al_map_rgba(255, 255, 255, 255);

   return tls->current_blender.blend_color;
}


/* Function: al_get_separate_blender
 */
void al_get_separate_blender(int *op, int *src, int *dst,
   int *alpha_op, int *alpha_src, int *alpha_dst)
{
   thread_local_state *tls;
   ALLEGRO_BLENDER *b;

   if ((tls = tls_get()) == NULL)
      return;

   b = &tls->current_blender;

   if (op)
      *op = b->blend_op;

   if (src)
      *src = b->blend_source;

   if (dst)
      *dst = b->blend_dest;

   if (alpha_op)
      *alpha_op = b->blend_alpha_op;

   if (alpha_src)
      *alpha_src = b->blend_alpha_source;

   if (alpha_dst)
      *alpha_dst = b->blend_alpha_dest;
}



/* Function: al_set_new_bitmap_format
 */
void al_set_new_bitmap_format(int format)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->new_bitmap_format = format;
}



/* Function: al_set_new_bitmap_flags
 */
void al_set_new_bitmap_flags(int flags)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;

   tls->new_bitmap_flags = flags;
}



/* Function: al_add_new_bitmap_flag
 */
void al_add_new_bitmap_flag(int flag)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->new_bitmap_flags |= flag;
}



/* Function: al_get_new_bitmap_format
 */
int al_get_new_bitmap_format(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return 0;
   return tls->new_bitmap_format;
}



/* Function: al_get_new_bitmap_flags
 */
int al_get_new_bitmap_flags(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return 0;
   return tls->new_bitmap_flags;
}



/* Function: al_store_state
 */
void al_store_state(ALLEGRO_STATE *state, int flags)
{
   thread_local_state *tls;
   INTERNAL_STATE *stored;

   if ((tls = tls_get()) == NULL)
      return;

   stored = (void *)state;
   stored->flags = flags;

#define _STORE(x) (stored->tls.x = tls->x)

   if (flags & ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS) {
      _STORE(new_display_flags);
      _STORE(new_display_refresh_rate);
      _STORE(new_display_adapter);
      _STORE(new_window_x);
      _STORE(new_window_y);
      _STORE(new_display_settings);
      _al_sane_strncpy(stored->tls.new_window_title, tls->new_window_title,
                       strlen(tls->new_window_title));
   }

   if (flags & ALLEGRO_STATE_NEW_BITMAP_PARAMETERS) {
      _STORE(new_bitmap_format);
      _STORE(new_bitmap_flags);
      _STORE(new_bitmap_wrap_u);
      _STORE(new_bitmap_wrap_v);
   }

   if (flags & ALLEGRO_STATE_DISPLAY) {
      _STORE(current_display);
   }

   if (flags & ALLEGRO_STATE_TARGET_BITMAP) {
      _STORE(target_bitmap);
   }

   if (flags & ALLEGRO_STATE_BLENDER) {
      stored->stored_blender = tls->current_blender;
   }

   if (flags & ALLEGRO_STATE_NEW_FILE_INTERFACE) {
      _STORE(new_file_interface);
      _STORE(fs_interface);
   }

   if (flags & ALLEGRO_STATE_TRANSFORM) {
      ALLEGRO_BITMAP *target = al_get_target_bitmap();
      if (!target)
         al_identity_transform(&stored->stored_transform);
      else
         stored->stored_transform = target->transform;
   }

   if (flags & ALLEGRO_STATE_PROJECTION_TRANSFORM) {
      ALLEGRO_BITMAP *target = al_get_target_bitmap();
      if (target) {
         stored->stored_projection_transform = target->proj_transform;
      }
   }

#undef _STORE
}



/* Function: al_restore_state
 */
void al_restore_state(ALLEGRO_STATE const *state)
{
   thread_local_state *tls;
   INTERNAL_STATE *stored;
   int flags;

   if ((tls = tls_get()) == NULL)
      return;

   stored = (void *)state;
   flags = stored->flags;

#define _RESTORE(x) (tls->x = stored->tls.x)

   if (flags & ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS) {
      _RESTORE(new_display_flags);
      _RESTORE(new_display_refresh_rate);
      _RESTORE(new_display_adapter);
      _RESTORE(new_window_x);
      _RESTORE(new_window_y);
      _RESTORE(new_display_settings);
      _al_sane_strncpy(tls->new_window_title, stored->tls.new_window_title,
                       strlen(tls->new_window_title));
   }

   if (flags & ALLEGRO_STATE_NEW_BITMAP_PARAMETERS) {
      _RESTORE(new_bitmap_format);
      _RESTORE(new_bitmap_flags);
      _RESTORE(new_bitmap_wrap_u);
      _RESTORE(new_bitmap_wrap_v);
   }

   if (flags & ALLEGRO_STATE_DISPLAY) {
      if (tls->current_display != stored->tls.current_display) {
         _al_set_current_display_only(stored->tls.current_display);
         ASSERT(tls->current_display == stored->tls.current_display);
      }
   }

   if (flags & ALLEGRO_STATE_TARGET_BITMAP) {
      if (tls->target_bitmap != stored->tls.target_bitmap) {
         al_set_target_bitmap(stored->tls.target_bitmap);
         ASSERT(tls->target_bitmap == stored->tls.target_bitmap);
      }
   }

   if (flags & ALLEGRO_STATE_BLENDER) {
      tls->current_blender = stored->stored_blender;
   }

   if (flags & ALLEGRO_STATE_NEW_FILE_INTERFACE) {
      _RESTORE(new_file_interface);
      _RESTORE(fs_interface);
   }

   if (flags & ALLEGRO_STATE_TRANSFORM) {
      ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
      if (bitmap)
         al_use_transform(&stored->stored_transform);
   }

   if (flags & ALLEGRO_STATE_PROJECTION_TRANSFORM) {
      ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
      if (bitmap)
         al_use_projection_transform(&stored->stored_projection_transform);
   }

#undef _RESTORE
}



/* Function: al_get_new_file_interface
 * FIXME: added a work-around for the situation where TLS has not yet been
 * initialised when this function is called. This may happen if Allegro
 * tries to load a configuration file before the system has been
 * initialised. Should probably rethink the logic here...
 */
const ALLEGRO_FILE_INTERFACE *al_get_new_file_interface(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return &_al_file_interface_stdio;

   /* FIXME: this situation should never arise because tls_ has the stdio
    * interface set as a default, but it arises on OS X if
    * pthread_getspecific() is called before pthreads_thread_init()...
    */
   if (tls->new_file_interface)
      return tls->new_file_interface;
   else
      return &_al_file_interface_stdio;
}



/* Function: al_set_new_file_interface
 */
void al_set_new_file_interface(const ALLEGRO_FILE_INTERFACE *file_interface)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->new_file_interface = file_interface;
}



/* Function: al_get_fs_interface
 */
const ALLEGRO_FS_INTERFACE *al_get_fs_interface(void)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return &_al_fs_interface_stdio;

   if (tls->fs_interface)
      return tls->fs_interface;
   else
      return &_al_fs_interface_stdio;
}



/* Function: al_set_fs_interface
 */
void al_set_fs_interface(const ALLEGRO_FS_INTERFACE *fs_interface)
{
   thread_local_state *tls;

   if ((tls = tls_get()) == NULL)
      return;
   tls->fs_interface = fs_interface;
}



/* Function: al_set_standard_fs_interface
 */
void al_set_standard_fs_interface(void)
{
   al_set_fs_interface(&_al_fs_interface_stdio);
}


#define SETTER(name, value) \
{ \
   thread_local_state *tls; \
   if ((tls = tls_get()) == NULL) \
      return; \
   tls->name = value; \
}

#define GETTER(name, value) \
{ \
   thread_local_state *tls; \
   if ((tls = tls_get()) == NULL) \
      return value; \
   return tls->name; \
}

/* Function: al_get_errno
 */
int al_get_errno(void)
GETTER(allegro_errno, 0)

/* Function: al_set_errno
 */
void al_set_errno(int errnum)
SETTER(allegro_errno, errnum)

/* Function: al_get_new_bitmap_depth
 */
int al_get_new_bitmap_depth(void)
GETTER(new_bitmap_depth, 0)

/* Function: al_set_new_bitmap_depth
 */
void al_set_new_bitmap_depth(int depth)
SETTER(new_bitmap_depth, depth)

/* Function: al_get_new_bitmap_samples
 */
int al_get_new_bitmap_samples(void)
GETTER(new_bitmap_samples, 0)

/* Function: al_set_new_bitmap_samples
 */
void al_set_new_bitmap_samples(int samples)
SETTER(new_bitmap_samples, samples)

/* Function: al_get_bitmap_wrap
 */
void al_get_new_bitmap_wrap(ALLEGRO_BITMAP_WRAP *u, ALLEGRO_BITMAP_WRAP *v)
{
   ASSERT(u);
   ASSERT(v);

   thread_local_state *tls;
   if ((tls = tls_get()) == NULL)
      return;

   *u = tls->new_bitmap_wrap_u;
   *v = tls->new_bitmap_wrap_v;
}

/* Function: al_set_new_bitmap_wrap
 */
void al_set_new_bitmap_wrap(ALLEGRO_BITMAP_WRAP u, ALLEGRO_BITMAP_WRAP v)
{
   thread_local_state *tls;
   if ((tls = tls_get()) == NULL)
      return;
   tls->new_bitmap_wrap_u = u;
   tls->new_bitmap_wrap_v = v;
}

#ifdef ALLEGRO_ANDROID
JNIEnv *_al_android_get_jnienv(void)
GETTER(jnienv, 0)

void _al_android_set_jnienv(JNIEnv *jnienv)
SETTER(jnienv, jnienv)
#endif


int *_al_tls_get_dtor_owner_count(void)
{
   thread_local_state *tls;

   tls = tls_get();
   return &tls->dtor_owner_count;
}


/* vim: set sts=3 sw=3 et: */
