1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Thread local storage.
12  *
13  *      By Trent Gamblin.
14  *
15  */
16 
17 /* FIXME:
18  *
19  * There are several ways to get thread local storage:
20  *
21  * 1. pthreads.
22  * 2. __thread keyword in gcc.
23  * 3. __declspec(thread) in MSVC.
24  * 4. TLS API under Windows.
25  *
26  * Since pthreads is available from the system everywhere except in
27  * Windows, this is the only case which is problematic. It appears
28  * that except for old mingw versions (before gcc 4.2) we can simply
29  * use __thread, and for MSVC we can always use __declspec(thread):
30  *
31  * However there also is a WANT_TLS configuration variable which is on
32  * by default and forces use of the TLS API instead. At the same time,
33  * the implementation using the TLS API in this file does not work
34  * with static linking. Someone should either completely remove
35  * WANT_TLS, or fix the static linking case...
36  */
37 
38 #include <string.h>
39 #include "allegro5/allegro.h"
40 #include "allegro5/internal/aintern.h"
41 #include "allegro5/internal/aintern_bitmap.h"
42 #include "allegro5/internal/aintern_display.h"
43 #include "allegro5/internal/aintern_file.h"
44 #include "allegro5/internal/aintern_fshook.h"
45 #include "allegro5/internal/aintern_shader.h"
46 #include "allegro5/internal/aintern_tls.h"
47 
48 #ifdef ALLEGRO_ANDROID
49 #include "allegro5/internal/aintern_android.h"
50 #endif
51 
52 #if defined(ALLEGRO_MINGW32) && !defined(ALLEGRO_CFG_DLL_TLS)
53    /*
54     * MinGW < 4.2.1 doesn't have builtin thread local storage, so we
55     * must use the Windows API.
56     */
57    #if __GNUC__ < 4
58       #define ALLEGRO_CFG_DLL_TLS
59    #elif __GNUC__ == 4 && __GNUC_MINOR__ < 2
60       #define ALLEGRO_CFG_DLL_TLS
61    #elif __GNUC__ == 4 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ < 1
62       #define ALLEGRO_CFG_DLL_TLS
63    #endif
64 #endif
65 
66 
67 /* Thread local storage for various per-thread state. */
68 typedef struct thread_local_state {
69    /* New display parameters */
70    int new_display_flags;
71    int new_display_refresh_rate;
72    int new_display_adapter;
73    int new_window_x;
74    int new_window_y;
75    int new_bitmap_depth;
76    int new_bitmap_samples;
77    ALLEGRO_EXTRA_DISPLAY_SETTINGS new_display_settings;
78 
79    /* Current display */
80    ALLEGRO_DISPLAY *current_display;
81 
82    /* Target bitmap */
83    ALLEGRO_BITMAP *target_bitmap;
84 
85    /* Blender */
86    ALLEGRO_BLENDER current_blender;
87 
88    /* Bitmap parameters */
89    int new_bitmap_format;
90    int new_bitmap_flags;
91 
92    /* Files */
93    const ALLEGRO_FILE_INTERFACE *new_file_interface;
94    const ALLEGRO_FS_INTERFACE *fs_interface;
95 
96    /* Error code */
97    int allegro_errno;
98 
99    /* Title to use for a new window/display.
100     * This is a static buffer for API reasons.
101     */
102    char new_window_title[ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE + 1];
103 
104 #ifdef ALLEGRO_ANDROID
105    JNIEnv *jnienv;
106 #endif
107 
108    /* Destructor ownership count */
109    int dtor_owner_count;
110 } thread_local_state;
111 
112 
113 typedef struct INTERNAL_STATE {
114    thread_local_state tls;
115    ALLEGRO_BLENDER stored_blender;
116    ALLEGRO_TRANSFORM stored_transform;
117    ALLEGRO_TRANSFORM stored_projection_transform;
118    int flags;
119 } INTERNAL_STATE;
120 
121 ALLEGRO_STATIC_ASSERT(tls, sizeof(ALLEGRO_STATE) > sizeof(INTERNAL_STATE));
122 
123 
initialize_blender(ALLEGRO_BLENDER * b)124 static void initialize_blender(ALLEGRO_BLENDER *b)
125 {
126    b->blend_op = ALLEGRO_ADD;
127    b->blend_source = ALLEGRO_ONE,
128    b->blend_dest = ALLEGRO_INVERSE_ALPHA;
129    b->blend_alpha_op = ALLEGRO_ADD;
130    b->blend_alpha_source = ALLEGRO_ONE;
131    b->blend_alpha_dest = ALLEGRO_INVERSE_ALPHA;
132    b->blend_color = al_map_rgba_f(1.0f, 1.0f, 1.0f, 1.0f);
133 }
134 
135 
initialize_tls_values(thread_local_state * tls)136 static void initialize_tls_values(thread_local_state *tls)
137 {
138    memset(tls, 0, sizeof *tls);
139 
140    tls->new_display_adapter = ALLEGRO_DEFAULT_DISPLAY_ADAPTER;
141    tls->new_window_x = INT_MAX;
142    tls->new_window_y = INT_MAX;
143 
144    initialize_blender(&tls->current_blender);
145    tls->new_bitmap_flags = ALLEGRO_CONVERT_BITMAP;
146    tls->new_bitmap_format = ALLEGRO_PIXEL_FORMAT_ANY_WITH_ALPHA;
147    tls->new_file_interface = &_al_file_interface_stdio;
148    tls->fs_interface = &_al_fs_interface_stdio;
149    memset(tls->new_window_title, 0, ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE + 1);
150 
151    _al_fill_display_settings(&tls->new_display_settings);
152 }
153 
154 // FIXME: The TLS implementation below only works for dynamic linking
155 // right now - instead of using DllMain we should simply initialize
156 // on first request.
157 #ifdef ALLEGRO_STATICLINK
158    #undef ALLEGRO_CFG_DLL_TLS
159 #endif
160 
161 #if defined(ALLEGRO_CFG_DLL_TLS)
162    #include "tls_dll.inc"
163 #elif defined(ALLEGRO_MACOSX) || defined(ALLEGRO_IPHONE) || defined(ALLEGRO_ANDROID) || defined(ALLEGRO_RASPBERRYPI)
164    #include "tls_pthread.inc"
165 #else
166    #include "tls_native.inc"
167 #endif
168 
169 
170 
_al_reinitialize_tls_values(void)171 void _al_reinitialize_tls_values(void)
172 {
173    thread_local_state *tls;
174    if ((tls = tls_get()) == NULL)
175       return;
176    initialize_tls_values(tls);
177 }
178 
179 
180 
_al_set_new_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS * settings)181 void _al_set_new_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *settings)
182 {
183    thread_local_state *tls;
184    if ((tls = tls_get()) == NULL)
185       return;
186    memmove(&tls->new_display_settings, settings, sizeof(ALLEGRO_EXTRA_DISPLAY_SETTINGS));
187 }
188 
189 
190 
_al_get_new_display_settings(void)191 ALLEGRO_EXTRA_DISPLAY_SETTINGS *_al_get_new_display_settings(void)
192 {
193    thread_local_state *tls;
194 
195    if ((tls = tls_get()) == NULL)
196       return 0;
197    return &tls->new_display_settings;
198 }
199 
200 
201 /* Function: al_set_new_window_title
202  */
al_set_new_window_title(const char * title)203 void al_set_new_window_title(const char *title)
204 {
205    thread_local_state *tls;
206    size_t size;
207 
208    if ((tls = tls_get()) == NULL)
209       return;
210 
211    size = strlen(title);
212 
213    if (size > ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE) {
214       size = ALLEGRO_NEW_WINDOW_TITLE_MAX_SIZE;
215    }
216 
217    _al_sane_strncpy(tls->new_window_title, title, size + 1);
218 }
219 
220 
221 
222 /* Function: al_get_new_window_title
223  */
al_get_new_window_title(void)224 const char *al_get_new_window_title(void)
225 {
226    thread_local_state *tls;
227 
228    /* Return app name in case of error or if not set before. */
229    if ((tls = tls_get()) == NULL)
230       return al_get_app_name();
231 
232    if (strlen(tls->new_window_title) < 1)
233       return al_get_app_name();
234 
235 
236    return (const char *)tls->new_window_title;
237 }
238 
239 
240 
241 
242 /* Function: al_set_new_display_flags
243  */
al_set_new_display_flags(int flags)244 void al_set_new_display_flags(int flags)
245 {
246    thread_local_state *tls;
247 
248    if ((tls = tls_get()) == NULL)
249       return;
250    tls->new_display_flags = flags;
251 }
252 
253 
254 
255 /* Function: al_get_new_display_flags
256  */
al_get_new_display_flags(void)257 int al_get_new_display_flags(void)
258 {
259    thread_local_state *tls;
260 
261    if ((tls = tls_get()) == NULL)
262       return 0;
263    return tls->new_display_flags;
264 }
265 
266 
267 
268 /* Function: al_set_new_display_refresh_rate
269  */
al_set_new_display_refresh_rate(int refresh_rate)270 void al_set_new_display_refresh_rate(int refresh_rate)
271 {
272    thread_local_state *tls;
273 
274    if ((tls = tls_get()) == NULL)
275       return;
276    tls->new_display_refresh_rate = refresh_rate;
277 }
278 
279 
280 
281 /* Function: al_get_new_display_refresh_rate
282  */
al_get_new_display_refresh_rate(void)283 int al_get_new_display_refresh_rate(void)
284 {
285    thread_local_state *tls;
286 
287    if ((tls = tls_get()) == NULL)
288       return 0;
289    return tls->new_display_refresh_rate;
290 }
291 
292 
293 
294 /* Function: al_set_new_display_adapter
295  */
al_set_new_display_adapter(int adapter)296 void al_set_new_display_adapter(int adapter)
297 {
298    thread_local_state *tls;
299 
300    if ((tls = tls_get()) == NULL)
301       return;
302 
303    if (adapter < 0) {
304       tls->new_display_adapter = ALLEGRO_DEFAULT_DISPLAY_ADAPTER;
305    }
306    tls->new_display_adapter = adapter;
307 }
308 
309 
310 
311 /* Function: al_get_new_display_adapter
312  */
al_get_new_display_adapter(void)313 int al_get_new_display_adapter(void)
314 {
315    thread_local_state *tls;
316 
317    if ((tls = tls_get()) == NULL)
318       return ALLEGRO_DEFAULT_DISPLAY_ADAPTER;
319    return tls->new_display_adapter;
320 }
321 
322 
323 
324 /* Function: al_set_new_window_position
325  */
al_set_new_window_position(int x,int y)326 void al_set_new_window_position(int x, int y)
327 {
328    thread_local_state *tls;
329 
330    if ((tls = tls_get()) == NULL)
331       return;
332    tls->new_window_x = x;
333    tls->new_window_y = y;
334 }
335 
336 
337 /* Function: al_get_new_window_position
338  */
al_get_new_window_position(int * x,int * y)339 void al_get_new_window_position(int *x, int *y)
340 {
341    thread_local_state *tls;
342    int new_window_x = INT_MAX;
343    int new_window_y = INT_MAX;
344 
345    if ((tls = tls_get()) != NULL) {
346       new_window_x = tls->new_window_x;
347       new_window_y = tls->new_window_y;
348    }
349 
350    if (x)
351       *x = new_window_x;
352    if (y)
353       *y = new_window_y;
354 }
355 
356 
357 
358 /* Make the given display current, without changing the target bitmap.
359  * This is used internally to change the current display transiently.
360  */
_al_set_current_display_only(ALLEGRO_DISPLAY * display)361 bool _al_set_current_display_only(ALLEGRO_DISPLAY *display)
362 {
363    thread_local_state *tls;
364 
365    if ((tls = tls_get()) == NULL)
366       return false;
367 
368    if (tls->current_display &&
369          tls->current_display->vt &&
370          tls->current_display->vt->unset_current_display) {
371       tls->current_display->vt->unset_current_display(tls->current_display);
372       tls->current_display = NULL;
373    }
374 
375    if (display &&
376          display->vt &&
377          display->vt->set_current_display) {
378       if (!display->vt->set_current_display(display))
379          return false;
380    }
381 
382    tls->current_display = display;
383    return true;
384 }
385 
386 
387 
388 /* Function: al_get_current_display
389  */
al_get_current_display(void)390 ALLEGRO_DISPLAY *al_get_current_display(void)
391 {
392    thread_local_state *tls;
393 
394    if ((tls = tls_get()) == NULL)
395       return NULL;
396    return tls->current_display;
397 }
398 
399 
400 
401 /* Function: al_set_target_bitmap
402  */
al_set_target_bitmap(ALLEGRO_BITMAP * bitmap)403 void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap)
404 {
405    thread_local_state *tls;
406    ALLEGRO_DISPLAY *old_display;
407    ALLEGRO_DISPLAY *new_display;
408    ALLEGRO_SHADER *old_shader;
409    ALLEGRO_SHADER *new_shader;
410    bool same_shader;
411    int bitmap_flags = bitmap ? al_get_bitmap_flags(bitmap) : 0;
412 
413    ASSERT(!al_is_bitmap_drawing_held());
414 
415    if (bitmap) {
416       if (bitmap->parent) {
417          bitmap->parent->dirty = true;
418       }
419       else {
420          bitmap->dirty = true;
421       }
422    }
423 
424    if ((tls = tls_get()) == NULL)
425       return;
426 
427    old_display = tls->current_display;
428 
429    if (tls->target_bitmap)
430       old_shader = tls->target_bitmap->shader;
431    else
432       old_shader = NULL;
433 
434    if (bitmap == NULL) {
435       /* Explicitly releasing the current rendering context. */
436       new_display = NULL;
437       new_shader = NULL;
438    }
439    else if (bitmap_flags & ALLEGRO_MEMORY_BITMAP) {
440       /* Setting a memory bitmap doesn't change the rendering context. */
441       new_display = old_display;
442       new_shader = NULL;
443    }
444    else {
445       new_display = _al_get_bitmap_display(bitmap);
446       new_shader = bitmap->shader;
447    }
448 
449    same_shader = (old_shader == new_shader && old_display == new_display);
450 
451    /* Unset the old shader if necessary. */
452    if (old_shader && !same_shader) {
453       old_shader->vt->unuse_shader(old_shader, old_display);
454    }
455 
456    /* Change the rendering context if necessary. */
457    if (old_display != new_display) {
458       if (old_display &&
459             old_display->vt &&
460             old_display->vt->unset_current_display) {
461          old_display->vt->unset_current_display(old_display);
462       }
463 
464       tls->current_display = new_display;
465 
466       if (new_display &&
467             new_display->vt &&
468             new_display->vt->set_current_display) {
469          new_display->vt->set_current_display(new_display);
470       }
471    }
472 
473    /* Change the target bitmap itself. */
474    tls->target_bitmap = bitmap;
475 
476    if (bitmap &&
477          !(bitmap_flags & ALLEGRO_MEMORY_BITMAP) &&
478          new_display &&
479          new_display->vt &&
480          new_display->vt->set_target_bitmap)
481    {
482       new_display->vt->set_target_bitmap(new_display, bitmap);
483 
484       /* Set the new shader if necessary.  This should done before the
485        * update_transformation call, which will also update the shader's
486        * al_projview_matrix variable.
487        */
488       if (!same_shader || !new_shader) {
489          al_use_shader(new_shader);
490       }
491 
492       new_display->vt->update_transformation(new_display, bitmap);
493    }
494 }
495 
496 
497 
498 /* Function: al_set_target_backbuffer
499  */
al_set_target_backbuffer(ALLEGRO_DISPLAY * display)500 void al_set_target_backbuffer(ALLEGRO_DISPLAY *display)
501 {
502    al_set_target_bitmap(al_get_backbuffer(display));
503 }
504 
505 
506 
507 /* Function: al_get_target_bitmap
508  */
al_get_target_bitmap(void)509 ALLEGRO_BITMAP *al_get_target_bitmap(void)
510 {
511    thread_local_state *tls;
512 
513    if ((tls = tls_get()) == NULL)
514       return 0;
515    return tls->target_bitmap;
516 }
517 
518 
519 
520 /* Function: al_set_blender
521  */
al_set_blender(int op,int src,int dst)522 void al_set_blender(int op, int src, int dst)
523 {
524    al_set_separate_blender(op, src, dst, op, src, dst);
525 }
526 
527 
528 
529 /* Function: al_set_blend_color
530 */
al_set_blend_color(ALLEGRO_COLOR color)531 void al_set_blend_color(ALLEGRO_COLOR color)
532 {
533    thread_local_state *tls;
534 
535    if ((tls = tls_get()) == NULL)
536       return;
537 
538    tls->current_blender.blend_color = color;
539 }
540 
541 
542 /* Function: al_set_separate_blender
543  */
al_set_separate_blender(int op,int src,int dst,int alpha_op,int alpha_src,int alpha_dst)544 void al_set_separate_blender(int op, int src, int dst,
545    int alpha_op, int alpha_src, int alpha_dst)
546 {
547    thread_local_state *tls;
548    ALLEGRO_BLENDER *b;
549 
550    ASSERT(op >= 0 && op < ALLEGRO_NUM_BLEND_OPERATIONS);
551    ASSERT(src >= 0 && src < ALLEGRO_NUM_BLEND_MODES);
552    ASSERT(dst >= 0 && src < ALLEGRO_NUM_BLEND_MODES);
553    ASSERT(alpha_op >= 0 && alpha_op < ALLEGRO_NUM_BLEND_OPERATIONS);
554    ASSERT(alpha_src >= 0 && alpha_src < ALLEGRO_NUM_BLEND_MODES);
555    ASSERT(alpha_dst >= 0 && alpha_dst < ALLEGRO_NUM_BLEND_MODES);
556 
557    if ((tls = tls_get()) == NULL)
558       return;
559 
560    b = &tls->current_blender;
561 
562    b->blend_op = op;
563    b->blend_source = src;
564    b->blend_dest = dst;
565    b->blend_alpha_op = alpha_op;
566    b->blend_alpha_source = alpha_src;
567    b->blend_alpha_dest = alpha_dst;
568 }
569 
570 
571 
572 /* Function: al_get_blender
573  */
al_get_blender(int * op,int * src,int * dst)574 void al_get_blender(int *op, int *src, int *dst)
575 {
576    al_get_separate_blender(op, src, dst, NULL, NULL, NULL);
577 }
578 
579 
580 
581 /* Function: al_get_blend_color
582 */
al_get_blend_color(void)583 ALLEGRO_COLOR al_get_blend_color(void)
584 {
585    thread_local_state *tls;
586 
587    if ((tls = tls_get()) == NULL)
588       return al_map_rgba(255, 255, 255, 255);
589 
590    return tls->current_blender.blend_color;
591 }
592 
593 
594 /* Function: al_get_separate_blender
595  */
al_get_separate_blender(int * op,int * src,int * dst,int * alpha_op,int * alpha_src,int * alpha_dst)596 void al_get_separate_blender(int *op, int *src, int *dst,
597    int *alpha_op, int *alpha_src, int *alpha_dst)
598 {
599    thread_local_state *tls;
600    ALLEGRO_BLENDER *b;
601 
602    if ((tls = tls_get()) == NULL)
603       return;
604 
605    b = &tls->current_blender;
606 
607    if (op)
608       *op = b->blend_op;
609 
610    if (src)
611       *src = b->blend_source;
612 
613    if (dst)
614       *dst = b->blend_dest;
615 
616    if (alpha_op)
617       *alpha_op = b->blend_alpha_op;
618 
619    if (alpha_src)
620       *alpha_src = b->blend_alpha_source;
621 
622    if (alpha_dst)
623       *alpha_dst = b->blend_alpha_dest;
624 }
625 
626 
627 
628 /* Function: al_set_new_bitmap_format
629  */
al_set_new_bitmap_format(int format)630 void al_set_new_bitmap_format(int format)
631 {
632    thread_local_state *tls;
633 
634    if ((tls = tls_get()) == NULL)
635       return;
636    tls->new_bitmap_format = format;
637 }
638 
639 
640 
641 /* Function: al_set_new_bitmap_flags
642  */
al_set_new_bitmap_flags(int flags)643 void al_set_new_bitmap_flags(int flags)
644 {
645    thread_local_state *tls;
646 
647    if ((tls = tls_get()) == NULL)
648       return;
649 
650    tls->new_bitmap_flags = flags;
651 }
652 
653 
654 
655 /* Function: al_add_new_bitmap_flag
656  */
al_add_new_bitmap_flag(int flag)657 void al_add_new_bitmap_flag(int flag)
658 {
659    thread_local_state *tls;
660 
661    if ((tls = tls_get()) == NULL)
662       return;
663    tls->new_bitmap_flags |= flag;
664 }
665 
666 
667 
668 /* Function: al_get_new_bitmap_format
669  */
al_get_new_bitmap_format(void)670 int al_get_new_bitmap_format(void)
671 {
672    thread_local_state *tls;
673 
674    if ((tls = tls_get()) == NULL)
675       return 0;
676    return tls->new_bitmap_format;
677 }
678 
679 
680 
681 /* Function: al_get_new_bitmap_flags
682  */
al_get_new_bitmap_flags(void)683 int al_get_new_bitmap_flags(void)
684 {
685    thread_local_state *tls;
686 
687    if ((tls = tls_get()) == NULL)
688       return 0;
689    return tls->new_bitmap_flags;
690 }
691 
692 
693 
694 /* Function: al_store_state
695  */
al_store_state(ALLEGRO_STATE * state,int flags)696 void al_store_state(ALLEGRO_STATE *state, int flags)
697 {
698    thread_local_state *tls;
699    INTERNAL_STATE *stored;
700 
701    if ((tls = tls_get()) == NULL)
702       return;
703 
704    stored = (void *)state;
705    stored->flags = flags;
706 
707 #define _STORE(x) (stored->tls.x = tls->x)
708 
709    if (flags & ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS) {
710       _STORE(new_display_flags);
711       _STORE(new_display_refresh_rate);
712       _STORE(new_display_adapter);
713       _STORE(new_window_x);
714       _STORE(new_window_y);
715       _STORE(new_display_settings);
716       _al_sane_strncpy(stored->tls.new_window_title, tls->new_window_title,
717                        strlen(tls->new_window_title));
718    }
719 
720    if (flags & ALLEGRO_STATE_NEW_BITMAP_PARAMETERS) {
721       _STORE(new_bitmap_format);
722       _STORE(new_bitmap_flags);
723    }
724 
725    if (flags & ALLEGRO_STATE_DISPLAY) {
726       _STORE(current_display);
727    }
728 
729    if (flags & ALLEGRO_STATE_TARGET_BITMAP) {
730       _STORE(target_bitmap);
731    }
732 
733    if (flags & ALLEGRO_STATE_BLENDER) {
734       stored->stored_blender = tls->current_blender;
735    }
736 
737    if (flags & ALLEGRO_STATE_NEW_FILE_INTERFACE) {
738       _STORE(new_file_interface);
739       _STORE(fs_interface);
740    }
741 
742    if (flags & ALLEGRO_STATE_TRANSFORM) {
743       ALLEGRO_BITMAP *target = al_get_target_bitmap();
744       if (!target)
745          al_identity_transform(&stored->stored_transform);
746       else
747          stored->stored_transform = target->transform;
748    }
749 
750    if (flags & ALLEGRO_STATE_PROJECTION_TRANSFORM) {
751       ALLEGRO_BITMAP *target = al_get_target_bitmap();
752       if (target) {
753          stored->stored_projection_transform = target->proj_transform;
754       }
755    }
756 
757 #undef _STORE
758 }
759 
760 
761 
762 /* Function: al_restore_state
763  */
al_restore_state(ALLEGRO_STATE const * state)764 void al_restore_state(ALLEGRO_STATE const *state)
765 {
766    thread_local_state *tls;
767    INTERNAL_STATE *stored;
768    int flags;
769 
770    if ((tls = tls_get()) == NULL)
771       return;
772 
773    stored = (void *)state;
774    flags = stored->flags;
775 
776 #define _RESTORE(x) (tls->x = stored->tls.x)
777 
778    if (flags & ALLEGRO_STATE_NEW_DISPLAY_PARAMETERS) {
779       _RESTORE(new_display_flags);
780       _RESTORE(new_display_refresh_rate);
781       _RESTORE(new_display_adapter);
782       _RESTORE(new_window_x);
783       _RESTORE(new_window_y);
784       _RESTORE(new_display_settings);
785       _al_sane_strncpy(tls->new_window_title, stored->tls.new_window_title,
786                        strlen(tls->new_window_title));
787    }
788 
789    if (flags & ALLEGRO_STATE_NEW_BITMAP_PARAMETERS) {
790       _RESTORE(new_bitmap_format);
791       _RESTORE(new_bitmap_flags);
792    }
793 
794    if (flags & ALLEGRO_STATE_DISPLAY) {
795       if (tls->current_display != stored->tls.current_display) {
796          _al_set_current_display_only(stored->tls.current_display);
797          ASSERT(tls->current_display == stored->tls.current_display);
798       }
799    }
800 
801    if (flags & ALLEGRO_STATE_TARGET_BITMAP) {
802       if (tls->target_bitmap != stored->tls.target_bitmap) {
803          al_set_target_bitmap(stored->tls.target_bitmap);
804          ASSERT(tls->target_bitmap == stored->tls.target_bitmap);
805       }
806    }
807 
808    if (flags & ALLEGRO_STATE_BLENDER) {
809       tls->current_blender = stored->stored_blender;
810    }
811 
812    if (flags & ALLEGRO_STATE_NEW_FILE_INTERFACE) {
813       _RESTORE(new_file_interface);
814       _RESTORE(fs_interface);
815    }
816 
817    if (flags & ALLEGRO_STATE_TRANSFORM) {
818       ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
819       if (bitmap)
820          al_use_transform(&stored->stored_transform);
821    }
822 
823    if (flags & ALLEGRO_STATE_PROJECTION_TRANSFORM) {
824       ALLEGRO_BITMAP *bitmap = al_get_target_bitmap();
825       if (bitmap)
826          al_use_projection_transform(&stored->stored_projection_transform);
827    }
828 
829 #undef _RESTORE
830 }
831 
832 
833 
834 /* Function: al_get_new_file_interface
835  * FIXME: added a work-around for the situation where TLS has not yet been
836  * initialised when this function is called. This may happen if Allegro
837  * tries to load a configuration file before the system has been
838  * initialised. Should probably rethink the logic here...
839  */
al_get_new_file_interface(void)840 const ALLEGRO_FILE_INTERFACE *al_get_new_file_interface(void)
841 {
842    thread_local_state *tls;
843 
844    if ((tls = tls_get()) == NULL)
845       return &_al_file_interface_stdio;
846 
847    /* FIXME: this situation should never arise because tls_ has the stdio
848     * interface set as a default, but it arises on OS X if
849     * pthread_getspecific() is called before pthreads_thread_init()...
850     */
851    if (tls->new_file_interface)
852       return tls->new_file_interface;
853    else
854       return &_al_file_interface_stdio;
855 }
856 
857 
858 
859 /* Function: al_set_new_file_interface
860  */
al_set_new_file_interface(const ALLEGRO_FILE_INTERFACE * file_interface)861 void al_set_new_file_interface(const ALLEGRO_FILE_INTERFACE *file_interface)
862 {
863    thread_local_state *tls;
864 
865    if ((tls = tls_get()) == NULL)
866       return;
867    tls->new_file_interface = file_interface;
868 }
869 
870 
871 
872 /* Function: al_get_fs_interface
873  */
al_get_fs_interface(void)874 const ALLEGRO_FS_INTERFACE *al_get_fs_interface(void)
875 {
876    thread_local_state *tls;
877 
878    if ((tls = tls_get()) == NULL)
879       return &_al_fs_interface_stdio;
880 
881    if (tls->fs_interface)
882       return tls->fs_interface;
883    else
884       return &_al_fs_interface_stdio;
885 }
886 
887 
888 
889 /* Function: al_set_fs_interface
890  */
al_set_fs_interface(const ALLEGRO_FS_INTERFACE * fs_interface)891 void al_set_fs_interface(const ALLEGRO_FS_INTERFACE *fs_interface)
892 {
893    thread_local_state *tls;
894 
895    if ((tls = tls_get()) == NULL)
896       return;
897    tls->fs_interface = fs_interface;
898 }
899 
900 
901 
902 /* Function: al_set_standard_fs_interface
903  */
al_set_standard_fs_interface(void)904 void al_set_standard_fs_interface(void)
905 {
906    al_set_fs_interface(&_al_fs_interface_stdio);
907 }
908 
909 
910 #define SETTER(name, value) \
911 { \
912    thread_local_state *tls; \
913    if ((tls = tls_get()) == NULL) \
914       return; \
915    tls->name = value; \
916 }
917 
918 #define GETTER(name, value) \
919 { \
920    thread_local_state *tls; \
921    if ((tls = tls_get()) == NULL) \
922       return value; \
923    return tls->name; \
924 }
925 
926 /* Function: al_get_errno
927  */
al_get_errno(void)928 int al_get_errno(void)
929 GETTER(allegro_errno, 0)
930 
931 /* Function: al_set_errno
932  */
933 void al_set_errno(int errnum)
934 SETTER(allegro_errno, errnum)
935 
936 /* Function: al_get_new_bitmap_depth
937  */
938 int al_get_new_bitmap_depth(void)
939 GETTER(new_bitmap_depth, 0)
940 
941 /* Function: al_set_new_bitmap_depth
942  */
943 void al_set_new_bitmap_depth(int depth)
944 SETTER(new_bitmap_depth, depth)
945 
946 /* Function: al_get_new_bitmap_samples
947  */
948 int al_get_new_bitmap_samples(void)
949 GETTER(new_bitmap_samples, 0)
950 
951 /* Function: al_set_new_bitmap_samples
952  */
953 void al_set_new_bitmap_samples(int samples)
954 SETTER(new_bitmap_samples, samples)
955 
956 
957 
958 #ifdef ALLEGRO_ANDROID
959 JNIEnv *_al_android_get_jnienv(void)
960 GETTER(jnienv, 0)
961 
962 void _al_android_set_jnienv(JNIEnv *jnienv)
963 SETTER(jnienv, jnienv)
964 #endif
965 
966 
967 int *_al_tls_get_dtor_owner_count(void)
968 {
969    thread_local_state *tls;
970 
971    tls = tls_get();
972    return &tls->dtor_owner_count;
973 }
974 
975 
976 /* vim: set sts=3 sw=3 et: */
977