src/dynapi/SDL_dynapi.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 22 Jun 2015 23:36:06 -0700
changeset 9776 952ff8a5076f
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
Fixed bug 3030 - SDL_RecreateWindow fails to restore title, icon, etc.

Adam M.

It loses the title and icon when window recreation fails. For instance, this may happen when trying to create an OpenGL ES window on a system that doesn't support it. But at that point, the title and icon have already been lost.
icculus@8094
     1
/*
icculus@8094
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
icculus@8094
     4
icculus@8094
     5
  This software is provided 'as-is', without any express or implied
icculus@8094
     6
  warranty.  In no event will the authors be held liable for any damages
icculus@8094
     7
  arising from the use of this software.
icculus@8094
     8
icculus@8094
     9
  Permission is granted to anyone to use this software for any purpose,
icculus@8094
    10
  including commercial applications, and to alter it and redistribute it
icculus@8094
    11
  freely, subject to the following restrictions:
icculus@8094
    12
icculus@8094
    13
  1. The origin of this software must not be misrepresented; you must not
icculus@8094
    14
     claim that you wrote the original software. If you use this software
icculus@8094
    15
     in a product, an acknowledgment in the product documentation would be
icculus@8094
    16
     appreciated but is not required.
icculus@8094
    17
  2. Altered source versions must be plainly marked as such, and must not be
icculus@8094
    18
     misrepresented as being the original software.
icculus@8094
    19
  3. This notice may not be removed or altered from any source distribution.
icculus@8094
    20
*/
icculus@8094
    21
icculus@8094
    22
#include "SDL_config.h"
icculus@8094
    23
#include "SDL_dynapi.h"
icculus@8094
    24
icculus@8094
    25
#if SDL_DYNAMIC_API
icculus@8094
    26
icculus@8094
    27
#include "SDL.h"
icculus@8094
    28
icculus@8094
    29
/* !!! FIXME: Shouldn't these be included in SDL.h? */
icculus@8094
    30
#include "SDL_shape.h"
icculus@8094
    31
#include "SDL_syswm.h"
icculus@8094
    32
icculus@8094
    33
/* This is the version of the dynamic API. This doesn't match the SDL version
icculus@8094
    34
   and should not change until there's been a major revamp in API/ABI.
icculus@8094
    35
   So 2.0.5 adds functions over 2.0.4? This number doesn't change;
icculus@8094
    36
   the sizeof (jump_table) changes instead. But 2.1.0 changes how a function
icculus@8094
    37
   works in an incompatible way or removes a function? This number changes,
icculus@8094
    38
   since sizeof (jump_table) isn't sufficient anymore. It's likely
icculus@8094
    39
   we'll forget to bump every time we add a function, so this is the
icculus@8094
    40
   failsafe switch for major API change decisions. Respect it and use it
icculus@8094
    41
   sparingly. */
icculus@8094
    42
#define SDL_DYNAPI_VERSION 1
icculus@8094
    43
icculus@8094
    44
static void SDL_InitDynamicAPI(void);
icculus@8094
    45
icculus@8094
    46
icculus@8094
    47
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
icculus@8094
    48
   Even self-contained stuff might call SDL_Error and break everything. */
icculus@8094
    49
icculus@8094
    50
icculus@8094
    51
/* behold, the macro salsa! */
icculus@8094
    52
icculus@8094
    53
/* !!! FIXME: ...disabled...until we write it.  :) */
icculus@8094
    54
#define DISABLE_JUMP_MAGIC 1
icculus@8094
    55
icculus@8094
    56
#if DISABLE_JUMP_MAGIC
icculus@8094
    57
/* Can't use the macro for varargs nonsense. This is atrocious. */
icculus@8094
    58
#define SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, logname, prio) \
slouken@8820
    59
    _static void SDL_Log##logname##name(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    60
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    61
        jump_table.SDL_LogMessageV(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
icculus@8094
    62
        va_end(ap); \
icculus@8094
    63
    }
icculus@8094
    64
icculus@8094
    65
#define SDL_DYNAPI_VARARGS(_static, name, initcall) \
slouken@8820
    66
    _static int SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    67
        char buf[512]; /* !!! FIXME: dynamic allocation */ \
icculus@8094
    68
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    69
        jump_table.SDL_vsnprintf(buf, sizeof (buf), fmt, ap); \
icculus@8094
    70
        va_end(ap); \
icculus@8094
    71
        return jump_table.SDL_SetError("%s", buf); \
icculus@8094
    72
    } \
slouken@8820
    73
    _static int SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    74
        int retval; va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    75
        retval = jump_table.SDL_vsscanf(buf, fmt, ap); \
icculus@8094
    76
        va_end(ap); \
icculus@8094
    77
        return retval; \
icculus@8094
    78
    } \
slouken@8820
    79
    _static int SDL_snprintf##name(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    80
        int retval; va_list ap; initcall; va_start(ap, fmt); \
slouken@8820
    81
        retval = jump_table.SDL_vsnprintf(buf, maxlen, fmt, ap); \
icculus@8094
    82
        va_end(ap); \
icculus@8094
    83
        return retval; \
icculus@8094
    84
    } \
slouken@8820
    85
    _static void SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    86
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    87
        jump_table.SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \
icculus@8094
    88
        va_end(ap); \
icculus@8094
    89
    } \
slouken@8820
    90
    _static void SDL_LogMessage##name(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
icculus@8094
    91
        va_list ap; initcall; va_start(ap, fmt); \
icculus@8094
    92
        jump_table.SDL_LogMessageV(category, priority, fmt, ap); \
icculus@8094
    93
        va_end(ap); \
icculus@8094
    94
    } \
icculus@8094
    95
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \
icculus@8094
    96
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \
icculus@8094
    97
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \
icculus@8094
    98
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Warn, WARN) \
icculus@8094
    99
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Error, ERROR) \
icculus@8094
   100
    SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Critical, CRITICAL)
icculus@8094
   101
#endif
icculus@8094
   102
icculus@8094
   103
icculus@8094
   104
/* Typedefs for function pointers for jump table, and predeclare funcs */
icculus@8094
   105
/* The DEFAULT funcs will init jump table and then call real function. */
icculus@8094
   106
/* The REAL funcs are the actual functions, name-mangled to not clash. */
icculus@8094
   107
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
icculus@8094
   108
    typedef rc (*SDL_DYNAPIFN_##fn) params; \
icculus@8094
   109
    static rc fn##_DEFAULT params; \
icculus@8094
   110
    extern rc fn##_REAL params;
icculus@8094
   111
#include "SDL_dynapi_procs.h"
icculus@8094
   112
#undef SDL_DYNAPI_PROC
icculus@8094
   113
icculus@8094
   114
/* The jump table! */
icculus@8094
   115
typedef struct {
icculus@8094
   116
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) SDL_DYNAPIFN_##fn fn;
icculus@8094
   117
    #include "SDL_dynapi_procs.h"
icculus@8094
   118
    #undef SDL_DYNAPI_PROC
icculus@8094
   119
} SDL_DYNAPI_jump_table;
icculus@8094
   120
icculus@8094
   121
/* Predeclare the default functions for initializing the jump table. */
icculus@8094
   122
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) static rc fn##_DEFAULT params;
icculus@8094
   123
#include "SDL_dynapi_procs.h"
icculus@8094
   124
#undef SDL_DYNAPI_PROC
icculus@8094
   125
icculus@8094
   126
/* The actual jump table. */
icculus@8094
   127
static SDL_DYNAPI_jump_table jump_table = {
icculus@8094
   128
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) fn##_DEFAULT,
icculus@8094
   129
    #include "SDL_dynapi_procs.h"
icculus@8094
   130
    #undef SDL_DYNAPI_PROC
icculus@8094
   131
};
icculus@8094
   132
icculus@8094
   133
/* Default functions init the function table then call right thing. */
icculus@8094
   134
#if DISABLE_JUMP_MAGIC
icculus@8094
   135
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
icculus@8094
   136
    static rc fn##_DEFAULT params { \
icculus@8094
   137
        SDL_InitDynamicAPI(); \
icculus@8094
   138
        ret jump_table.fn args; \
icculus@8094
   139
    }
icculus@8094
   140
#define SDL_DYNAPI_PROC_NO_VARARGS 1
icculus@8094
   141
#include "SDL_dynapi_procs.h"
icculus@8094
   142
#undef SDL_DYNAPI_PROC
icculus@8094
   143
#undef SDL_DYNAPI_PROC_NO_VARARGS
icculus@8094
   144
SDL_DYNAPI_VARARGS(static, _DEFAULT, SDL_InitDynamicAPI())
icculus@8094
   145
#else
icculus@8094
   146
/* !!! FIXME: need the jump magic. */
icculus@8094
   147
#error Write me.
icculus@8094
   148
#endif
icculus@8094
   149
icculus@8094
   150
/* Public API functions to jump into the jump table. */
icculus@8094
   151
#if DISABLE_JUMP_MAGIC
icculus@8094
   152
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
icculus@8094
   153
    rc fn params { ret jump_table.fn args; }
icculus@8094
   154
#define SDL_DYNAPI_PROC_NO_VARARGS 1
icculus@8094
   155
#include "SDL_dynapi_procs.h"
icculus@8094
   156
#undef SDL_DYNAPI_PROC
icculus@8094
   157
#undef SDL_DYNAPI_PROC_NO_VARARGS
icculus@8094
   158
SDL_DYNAPI_VARARGS(,,)
icculus@8094
   159
#else
icculus@8094
   160
/* !!! FIXME: need the jump magic. */
icculus@8094
   161
#error Write me.
icculus@8094
   162
#endif
icculus@8094
   163
icculus@8094
   164
icculus@8094
   165
icculus@8094
   166
/* Here's the exported entry point that fills in the jump table. */
icculus@8094
   167
/*  Use specific types when an "int" might suffice to keep this sane. */
icculus@8094
   168
typedef Sint32 (SDLCALL *SDL_DYNAPI_ENTRYFN)(Uint32 apiver, void *table, Uint32 tablesize);
icculus@8094
   169
extern DECLSPEC Sint32 SDLCALL SDL_DYNAPI_entry(Uint32, void *, Uint32);
icculus@8094
   170
icculus@8094
   171
Sint32
icculus@8094
   172
SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
icculus@8094
   173
{
icculus@8094
   174
    SDL_DYNAPI_jump_table *output_jump_table = (SDL_DYNAPI_jump_table *) table;
icculus@8094
   175
icculus@8094
   176
    if (apiver != SDL_DYNAPI_VERSION) {
icculus@8094
   177
        /* !!! FIXME: can maybe handle older versions? */
icculus@8094
   178
        return -1;  /* not compatible. */
icculus@8094
   179
    } else if (tablesize > sizeof (jump_table)) {
icculus@8094
   180
        return -1;  /* newer version of SDL with functions we can't provide. */
icculus@8094
   181
    }
icculus@8094
   182
icculus@8094
   183
    /* Init our jump table first. */
icculus@8094
   184
    #define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
icculus@8094
   185
    #include "SDL_dynapi_procs.h"
icculus@8094
   186
    #undef SDL_DYNAPI_PROC
icculus@8094
   187
icculus@8094
   188
    /* Then the external table... */
icculus@8094
   189
    if (output_jump_table != &jump_table) {
icculus@8094
   190
        jump_table.SDL_memcpy(output_jump_table, &jump_table, tablesize);
icculus@8094
   191
    }
icculus@8094
   192
icculus@8094
   193
    /* Safe to call SDL functions now; jump table is initialized! */
icculus@8094
   194
icculus@8094
   195
    return 0;  /* success! */
icculus@8094
   196
}
icculus@8094
   197
icculus@8094
   198
icculus@8094
   199
/* Obviously we can't use SDL_LoadObject() to load SDL.  :)  */
icculus@8094
   200
/* Also obviously, we never close the loaded library. */
icculus@8101
   201
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
icculus@8094
   202
#ifndef WIN32_LEAN_AND_MEAN
icculus@8094
   203
#define WIN32_LEAN_AND_MEAN 1
icculus@8094
   204
#endif
icculus@8094
   205
#include <windows.h>
icculus@8094
   206
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   207
{
icculus@8094
   208
    HANDLE lib = LoadLibraryA(fname);
icculus@9305
   209
    void *retval = NULL;
icculus@9305
   210
    if (lib) {
icculus@9305
   211
        retval = GetProcAddress(lib, sym);
icculus@9305
   212
        if (retval == NULL) {
icculus@9305
   213
            FreeLibrary(lib);
icculus@9305
   214
        }
icculus@9305
   215
    }
icculus@9305
   216
    return retval;
icculus@8094
   217
}
icculus@8094
   218
icculus@8094
   219
#elif defined(__HAIKU__)
icculus@8094
   220
#include <os/kernel/image.h>
icculus@8094
   221
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   222
{
icculus@8094
   223
    image_id lib = load_add_on(fname);
icculus@8094
   224
    void *retval = NULL;
icculus@9305
   225
    if (lib >= 0) {
icculus@9305
   226
        if (get_image_symbol(lib, sym, B_SYMBOL_TYPE_TEXT, &retval) != B_NO_ERROR) {
icculus@9305
   227
            unload_add_on(lib);
icculus@9305
   228
            retval = NULL;
icculus@9305
   229
        }
icculus@8094
   230
    }
icculus@8094
   231
    return retval;
icculus@8094
   232
}
icculus@8095
   233
#elif defined(unix) || defined(__unix__) || defined(__APPLE__)
icculus@8094
   234
#include <dlfcn.h>
icculus@8094
   235
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
icculus@8094
   236
{
icculus@8094
   237
    void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
icculus@9305
   238
    void *retval = NULL;
icculus@9305
   239
    if (lib != NULL) {
icculus@9305
   240
        retval = dlsym(lib, sym);
icculus@9305
   241
        if (retval == NULL) {
icculus@9305
   242
            dlclose(lib);
icculus@9305
   243
        }
icculus@9305
   244
    }
icculus@9305
   245
    return retval;
icculus@8094
   246
}
icculus@8094
   247
#else
icculus@8094
   248
#error Please define your platform.
icculus@8094
   249
#endif
icculus@8094
   250
icculus@8094
   251
icculus@8094
   252
static void
icculus@8094
   253
SDL_InitDynamicAPILocked(void)
icculus@8094
   254
{
icculus@8094
   255
    const char *libname = SDL_getenv_REAL("SDL_DYNAMIC_API");
icculus@8094
   256
    SDL_DYNAPI_ENTRYFN entry = SDL_DYNAPI_entry;  /* funcs from here by default. */
icculus@8094
   257
icculus@8094
   258
    if (libname) {
icculus@8094
   259
        entry = (SDL_DYNAPI_ENTRYFN) get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
icculus@8094
   260
        if (!entry) {
icculus@8094
   261
            /* !!! FIXME: fail to startup here instead? */
icculus@8094
   262
            /* !!! FIXME: definitely warn user. */
icculus@8094
   263
            /* Just fill in the function pointers from this library. */
icculus@8094
   264
            entry = SDL_DYNAPI_entry;
icculus@8094
   265
        }
icculus@8094
   266
    }
icculus@8094
   267
icculus@8094
   268
    if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
icculus@8094
   269
        /* !!! FIXME: fail to startup here instead? */
icculus@8094
   270
        /* !!! FIXME: definitely warn user. */
icculus@8094
   271
        /* Just fill in the function pointers from this library. */
icculus@8094
   272
        if (entry != SDL_DYNAPI_entry) {
icculus@8094
   273
            if (!SDL_DYNAPI_entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table))) {
icculus@8094
   274
                /* !!! FIXME: now we're screwed. Should definitely abort now. */
icculus@8094
   275
            }
icculus@8094
   276
        }
icculus@8094
   277
    }
icculus@8094
   278
icculus@8094
   279
    /* we intentionally never close the newly-loaded lib, of course. */
icculus@8094
   280
}
icculus@8094
   281
icculus@8094
   282
static void
icculus@8094
   283
SDL_InitDynamicAPI(void)
icculus@8094
   284
{
icculus@8094
   285
    /* So the theory is that every function in the jump table defaults to
icculus@8094
   286
     *  calling this function, and then replaces itself with a version that
icculus@8094
   287
     *  doesn't call this function anymore. But it's possible that, in an
icculus@8094
   288
     *  extreme corner case, you can have a second thread hit this function
icculus@8094
   289
     *  while the jump table is being initialized by the first.
icculus@8094
   290
     * In this case, a spinlock is really painful compared to what spinlocks
icculus@8094
   291
     *  _should_ be used for, but this would only happen once, and should be
icculus@8094
   292
     *  insanely rare, as you would have to spin a thread outside of SDL (as
icculus@8094
   293
     *  SDL_CreateThread() would also call this function before building the
icculus@8094
   294
     *  new thread).
icculus@8094
   295
     */
icculus@8094
   296
    static volatile SDL_bool already_initialized = SDL_FALSE;
icculus@8094
   297
icculus@8094
   298
    /* SDL_AtomicLock calls SDL mutex functions to emulate if
icculus@8094
   299
       SDL_ATOMIC_DISABLED, which we can't do here, so in such a
icculus@8094
   300
       configuration, you're on your own. */
icculus@8094
   301
    #if !SDL_ATOMIC_DISABLED
icculus@8094
   302
    static SDL_SpinLock lock = 0;
icculus@8094
   303
    SDL_AtomicLock_REAL(&lock);
icculus@8094
   304
    #endif
icculus@8094
   305
icculus@8094
   306
    if (!already_initialized) {
icculus@8094
   307
        SDL_InitDynamicAPILocked();
icculus@8094
   308
        already_initialized = SDL_TRUE;
icculus@8094
   309
    }
icculus@8094
   310
icculus@8094
   311
    #if !SDL_ATOMIC_DISABLED
icculus@8094
   312
    SDL_AtomicUnlock_REAL(&lock);
icculus@8094
   313
    #endif
icculus@8094
   314
}
icculus@8094
   315
icculus@8094
   316
#endif  /* SDL_DYNAMIC_API */
icculus@8094
   317
icculus@8094
   318
/* vi: set ts=4 sw=4 expandtab: */
icculus@8094
   319