| /* |
| Copyright (c) 2011-2013 NVIDIA Corporation |
| Copyright (c) 2011-2013 Cass Everitt |
| Copyright (c) 2013 Scott Nations |
| Copyright (c) 2013 Mathias Schott |
| Copyright (c) 2013 Nigel Stewart |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| Redistributions of source code must retain the above copyright notice, this |
| list of conditions and the following disclaimer. |
| |
| Redistributions in binary form must reproduce the above copyright notice, |
| this list of conditions and the following disclaimer in the documentation |
| and/or other materials provided with the distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "pch.h" /* For MS precompiled header support */ |
| |
| #include "RegalUtil.h" |
| |
| REGAL_GLOBAL_BEGIN |
| |
| #include <GL/Regal.h> |
| |
| #include <cerrno> |
| #include <string> |
| using namespace std; |
| |
| #include <boost/print/print_string.hpp> |
| #include <boost/print/string_list.hpp> |
| |
| using boost::print::print_string; |
| using boost::print::string_list; |
| |
| #include "RegalConfig.h" |
| |
| #if REGAL_SYS_X11 |
| #include <X11/Xatom.h> |
| #endif |
| |
| // alloca for VC8 |
| |
| #ifdef _MSC_VER |
| #include <malloc.h> |
| #define alloca _alloca |
| #endif |
| |
| #if REGAL_SYS_WGL |
| |
| typedef void *HMODULE; |
| |
| extern "C" { |
| HMODULE __stdcall LoadLibraryA(const char *filename); |
| void * __stdcall GetProcAddress(HMODULE hModule, const char *proc); |
| UINT __stdcall GetSystemDirectoryA(char *lpBuffer, UINT uSize); |
| } |
| |
| // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx |
| // In the Windows API ... the maximum length for a path is MAX_PATH, which is |
| // defined as 260 characters... |
| |
| #ifndef MAX_PATH |
| #define MAX_PATH 260 |
| #endif |
| |
| #endif |
| |
| REGAL_GLOBAL_END |
| |
| REGAL_NAMESPACE_BEGIN |
| |
| #if !REGAL_NO_ASSERT |
| #if REGAL_ASSERT_VERBOSE |
| void |
| AssertFunction(const char *file, const size_t line, const char *expr) |
| { |
| string message = print_string(file, " ", line, ": ", expr); |
| |
| #ifdef REGAL_ASSERT_FUNCTION |
| REGAL_ASSERT_FUNCTION(message); |
| #else |
| Error("Assertion Failed: ", message); |
| #endif |
| } |
| #else |
| void |
| AssertFunction(const char *expr) |
| { |
| #ifdef REGAL_ASSERT_FUNCTION |
| REGAL_ASSERT_FUNCTION(expr ? expr : ""); |
| #else |
| Error("Assertion Failed: ", expr ? expr : ""); |
| #endif |
| } |
| #endif |
| #endif |
| |
| inline const char * getEnvironment(const char * const var) |
| { |
| const char *ret = NULL; |
| |
| if (var) { |
| ret = getEnv(var); |
| |
| /* Treat empty environment variable the same as non-existant */ |
| if (!ret || *ret=='\0') |
| return NULL; |
| } |
| |
| return ret; |
| } |
| |
| enum Library |
| { |
| LIBRARY_ES1, |
| LIBRARY_ES2, |
| LIBRARY_GL, |
| LIBRARY_WGL, |
| LIBRARY_GLX, |
| LIBRARY_CGL, |
| LIBRARY_EGL |
| }; |
| |
| #ifndef __native_client__ |
| static |
| const char *libraryLocation(const Library &library) |
| { |
| const char *ret = NULL; |
| |
| if (library==LIBRARY_GL || library==LIBRARY_WGL || library==LIBRARY_GLX) |
| { |
| // First, try configured variable |
| |
| ret = Config::loadGL.length() ? Config::loadGL.c_str() : NULL; |
| |
| // Second, try default installation location |
| |
| if (!ret) |
| { |
| #if REGAL_SYS_OSX |
| ret = "/System/Library/Frameworks/OpenGL.framework/OpenGL"; |
| #endif |
| |
| #if REGAL_SYS_WGL |
| ret = getEnvironment("windir"); |
| |
| /* XP32, Cygwin */ |
| if (!ret) |
| ret = getEnvironment("WINDIR"); |
| |
| if (ret) |
| { |
| static string opengl32; |
| if (!opengl32.length()) |
| opengl32 = print_string(ret,"\\system32\\opengl32.dll"); |
| return opengl32.c_str(); |
| } |
| |
| char systemDirectory[MAX_PATH]; |
| UINT n = GetSystemDirectoryA(systemDirectory,MAX_PATH); |
| if (n>0 && n<MAX_PATH) |
| { |
| static string opengl32; |
| if (!opengl32.length()) |
| opengl32 = print_string(systemDirectory,"\\opengl32.dll"); |
| return opengl32.c_str(); |
| } |
| |
| return "opengl32.dll"; |
| #endif |
| |
| #if REGAL_SYS_GLX |
| |
| #if defined(__x86_64__) || defined(__x86_64) |
| const char * const candidates[] = { |
| "/usr/lib/amd64/libGL.so.1", // Solaris |
| "/usr/lib64/nvidia/libGL.so.1", // RedHat |
| "/usr/lib64/libGL.so.1", // RedHat |
| "/lib64/libGL.so.1", // Fedora 18 |
| "/usr/lib/nvidia-current/libGL.so.1", // Ubuntu NVIDIA |
| "/usr/lib/libGL.so.1", // Ubuntu |
| "/usr/lib/x86_64-linux-gnu/mesa/libGL.so.1", // Ubuntu via VMWare on Windows |
| NULL |
| }; |
| #else |
| const char * const candidates[] = { |
| "/usr/lib/nvidia-current-updates/libGL.so.1", // Ubuntu 12.04 32-bit NVIDIA |
| "/usr/lib32/nvidia-current/libGL.so.1", // Ubuntu NVIDIA |
| "/usr/lib32/libGL.so.1", // Ubuntu |
| "/usr/lib/fglrx/libGL.so.1", // Ubuntu 12.04 32-bit ATI Radeon HD 5450 |
| "/usr/lib/libGL.so.1", // RedHat & Solaris |
| "/usr/lib/i386-linux-gnu/mesa/libGL.so.1", // Ubuntu via VMWare on Windows |
| NULL |
| }; |
| #endif |
| for (const char * const *i = candidates; *i; ++i) { |
| if (fileExists(*i)) |
| return *i; |
| } |
| #endif |
| } |
| } |
| |
| // ES1 |
| |
| #if REGAL_SYS_ES1 |
| if (library==LIBRARY_ES1) |
| { |
| // First, try ... variable |
| |
| // Second, try default installation location |
| |
| if (!ret) |
| { |
| #if REGAL_SYS_ANDROID |
| return "/System/lib/libGLESv1_CM.so"; |
| #elif REGAL_SYS_EGL || REGAL_SYS_GLX |
| // TODO - ES1 for Linux? |
| #endif |
| } |
| } |
| #endif |
| |
| /* Ubuntu 12.04 x86 |
| |
| $ find /usr/lib/i386-linux-gnu/ -name "libEGL*" | xargs ls -la |
| lrwxrwxrwx 1 root root 18 Oct 12 05:02 /usr/lib/i386-linux-gnu/libEGL.so -> mesa-egl/libEGL.so |
| lrwxrwxrwx 1 root root 15 Oct 12 05:02 /usr/lib/i386-linux-gnu/mesa-egl/libEGL.so -> libEGL.so.1.0.0 |
| lrwxrwxrwx 1 root root 15 Oct 12 05:02 /usr/lib/i386-linux-gnu/mesa-egl/libEGL.so.1 -> libEGL.so.1.0.0 |
| -rw-r--r-- 1 root root 129660 Oct 12 05:02 /usr/lib/i386-linux-gnu/mesa-egl/libEGL.so.1.0.0 |
| |
| $ find /usr/lib/i386-linux-gnu/ -name "libGLES*" | xargs ls -la |
| lrwxrwxrwx 1 root root 18 Oct 12 05:02 /usr/lib/i386-linux-gnu/mesa-egl/libGLESv2.so.2 -> libGLESv2.so.2.0.0 |
| -rw-r--r-- 1 root root 16248 Oct 12 05:02 /usr/lib/i386-linux-gnu/mesa-egl/libGLESv2.so.2.0.0 |
| |
| */ |
| |
| // ES2 |
| |
| if (library==LIBRARY_ES2) |
| { |
| // First, try configured variable |
| |
| ret = Config::loadES2.length() ? Config::loadES2.c_str() : NULL; |
| |
| // Second, try default installation location |
| |
| if (!ret) |
| { |
| #if REGAL_SYS_EGL || REGAL_SYS_GLX |
| #if defined(__arm__) |
| return "/usr/lib/libGLESv2.so"; |
| #elif defined(__x86_64__) || defined(__x86_64) |
| return "/usr/lib/x86_64-linux-gnu/mesa-egl/libGLESv2.so.2"; |
| #else |
| return "/usr/lib/i386-linux-gnu/mesa-egl/libGLESv2.so.2"; |
| #endif |
| #endif |
| } |
| } |
| |
| // EGL |
| |
| if (library==LIBRARY_EGL) |
| { |
| // First, try configured variable |
| |
| ret = Config::loadEGL.length() ? Config::loadEGL.c_str() : NULL; |
| |
| // Second, try default installation location |
| |
| if (!ret) |
| { |
| #if REGAL_SYS_EGL |
| #if defined(__arm__) |
| return "/usr/lib/libEGL.so"; |
| #elif defined(__x86_64__) || defined(__x86_64) |
| return "/usr/lib/x86_64-linux-gnu/mesa-egl/libEGL.so"; |
| #else |
| return "/usr/lib/i386-linux-gnu/mesa-egl/libEGL.so"; |
| #endif |
| #endif |
| } |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| #if REGAL_SYS_OSX |
| |
| #include <dlfcn.h> |
| |
| void *GetProcAddress( const char *entry ) |
| { |
| if (!entry) |
| return NULL; |
| |
| static const char *lib_OpenGL_filename = "/System/Library/Frameworks/OpenGL.framework/OpenGL"; |
| static void *lib_OpenGL = NULL; |
| |
| static const char *lib_GL_filename = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"; |
| static void *lib_GL = NULL; |
| |
| if (!lib_OpenGL || !lib_GL) |
| { |
| // this chdir business is a hacky solution to avoid recursion |
| // when using libRegal as libGL via symlink and DYLD_LIBRARY_PATH=. |
| |
| char *oldCwd = getcwd(NULL,0); |
| chdir("/"); |
| |
| // CGL entry points are in OpenGL framework |
| |
| if (!lib_OpenGL) { |
| char temp_filename[] = "/tmp/tmp.Regal.XXXX"; |
| if (mktemp(temp_filename) != NULL ) { |
| if (symlink(lib_OpenGL_filename, temp_filename) == 0 ) { |
| lib_OpenGL = dlopen(temp_filename , RTLD_LOCAL | RTLD_NOW | RTLD_FIRST); |
| Info("Loading OpenGL from ",lib_OpenGL_filename,lib_OpenGL ? " succeeded." : " failed."); |
| remove( temp_filename ); |
| } |
| } |
| } |
| |
| // GL entry point are in libGL.dylib |
| |
| if (!lib_GL) { |
| char temp_filename[] = "/tmp/tmp.Regal.XXXX"; |
| if (mktemp(temp_filename) != NULL ) { |
| if (symlink(lib_GL_filename, temp_filename) == 0 ) { |
| lib_GL = dlopen(temp_filename , RTLD_LOCAL | RTLD_NOW | RTLD_FIRST); |
| Info("Loading libGL from ",lib_GL_filename,lib_GL ? " succeeded." : " failed."); |
| remove( temp_filename ); |
| } |
| } |
| } |
| |
| chdir(oldCwd); |
| free(oldCwd); |
| } |
| |
| if (lib_OpenGL && lib_GL) |
| { |
| void *sym = dlsym( lib_OpenGL, entry ); |
| Internal("Regal::GetProcAddress ",lib_OpenGL_filename," load of ",entry,sym ? " succeeded." : " failed."); |
| if (sym) |
| return sym; |
| sym = dlsym( lib_GL, entry ); |
| Internal("Regal::GetProcAddress ",lib_GL_filename," load of ",entry,sym ? " succeeded." : " failed."); |
| return sym; |
| } |
| |
| return NULL; |
| } |
| |
| #elif REGAL_SYS_PPAPI |
| |
| void *GetProcAddress( const char *entry ) |
| { |
| return NULL; |
| } |
| |
| #elif REGAL_SYS_IOS |
| |
| #include <dlfcn.h> |
| |
| void *GetProcAddress( const char * entry ) |
| { |
| if (!entry) |
| return NULL; |
| |
| static void *lib_OpenGLES = NULL; |
| if (!lib_OpenGLES) |
| lib_OpenGLES = dlopen( "/System/Library/Frameworks/OpenGLES.framework/OpenGLES", RTLD_LAZY ); |
| |
| if (lib_OpenGLES) { |
| void *sym = dlsym( lib_OpenGLES, entry ); |
| return sym; |
| } |
| |
| return NULL; |
| } |
| |
| #elif REGAL_SYS_EMSCRIPTEN |
| |
| // Emscripten-specific GetProcAddress. Can match EGL and GLES symbols. |
| |
| extern "C" void *eglGetProcAddress(const char *name); |
| |
| void *GetProcAddress(const char *entry) |
| { |
| return eglGetProcAddress(entry); |
| } |
| |
| #elif REGAL_SYS_GLX || REGAL_SYS_EGL |
| |
| // General purpose GetProcAddress for GLX or EGL, |
| // GL or ES 2.0 for Linux, so far. |
| |
| #include <dlfcn.h> |
| |
| void *GetProcAddress(const char *entry) |
| { |
| // Early-out for NULL entry name |
| |
| if (!entry) |
| return NULL; |
| |
| // GL ES 1.x |
| |
| #if REGAL_SYS_ES1 |
| |
| static void *lib_ES1 = NULL; |
| static const char *lib_ES1_filename = NULL; |
| |
| if (Regal::Config::sysES1) |
| { |
| // Search for OpenGL ES library as necessary |
| |
| if (!lib_ES1_filename) |
| { |
| lib_ES1_filename = libraryLocation(LIBRARY_ES1); |
| if (!lib_ES1_filename) |
| Warning("OpenGL ES 1.x library not found."); |
| } |
| |
| // Load the OpenGL ES 1.x library as necessary |
| |
| if (!lib_ES1 && lib_ES1_filename) |
| { |
| Info("Loading OpenGL ES 1.x from ",lib_ES1_filename); |
| lib_ES1 = dlopen( lib_ES1_filename, RTLD_LAZY ); |
| } |
| } |
| #endif |
| |
| // GL ES 2.0 |
| |
| #if REGAL_SYS_ES2 |
| |
| static void *lib_ES2 = NULL; |
| static const char *lib_ES2_filename = NULL; |
| |
| if (Regal::Config::sysES2) |
| { |
| // Search for OpenGL ES library (libGLESv2.so usually) as necessary |
| |
| if (!lib_ES2_filename) |
| { |
| lib_ES2_filename = libraryLocation(LIBRARY_ES2); |
| if (!lib_ES2_filename) |
| Warning("OpenGL ES 2.0 library not found."); |
| } |
| |
| // Load the OpenGL ES library as necessary |
| |
| if (!lib_ES2 && lib_ES2_filename) |
| { |
| Info("Loading OpenGL ES 2.0 from ",lib_ES2_filename); |
| lib_ES2 = dlopen( lib_ES2_filename, RTLD_LAZY ); |
| } |
| } |
| #endif |
| |
| // Desktop GL |
| |
| #if REGAL_SYS_GL |
| |
| static void *lib_GL = NULL; |
| static const char *lib_GL_filename = NULL; |
| |
| if (Regal::Config::sysGL) |
| { |
| // Search for OpenGL library (libGL.so.1 usually) as necessary |
| |
| if (!lib_GL_filename) |
| { |
| lib_GL_filename = libraryLocation(LIBRARY_GL); |
| if (!lib_GL_filename) |
| Warning("OpenGL library not found."); |
| } |
| |
| // Load the OpenGL library as necessary |
| |
| if (!lib_GL && lib_GL_filename) |
| { |
| Info("Loading OpenGL from ",lib_GL_filename); |
| |
| // We'd rather not use RTLD_GLOBAL, but the Linux Mesa |
| // GL implementation requires this for finding symbols |
| // in libglapi.so.0 |
| |
| lib_GL = dlopen( lib_GL_filename, RTLD_LAZY | RTLD_GLOBAL ); |
| } |
| } |
| #endif |
| |
| // EGL |
| |
| #if REGAL_SYS_EGL |
| |
| static void *lib_EGL = NULL; |
| static const char *lib_EGL_filename = NULL; |
| |
| if (Regal::Config::sysEGL) |
| { |
| // Search for EGL library (libEGL.so usually) as necessary |
| |
| if (!lib_EGL_filename) |
| { |
| lib_EGL_filename = libraryLocation(LIBRARY_EGL); |
| if (!lib_EGL_filename) |
| Warning("EGL library not found."); |
| } |
| |
| // Load the EGL library as necessary |
| |
| if (!lib_EGL && lib_EGL_filename) |
| { |
| Info("Loading EGL from ",lib_EGL_filename); |
| lib_EGL = dlopen( lib_EGL_filename, RTLD_LAZY ); |
| } |
| } |
| #endif |
| |
| // GLX |
| |
| #if REGAL_SYS_GLX |
| |
| static void *lib_GLX = NULL; |
| static const char *lib_GLX_filename = NULL; |
| |
| if (Regal::Config::sysGLX) |
| { |
| // Search for OpenGL library (libGL.so.1 usually) as necessary |
| |
| if (!lib_GLX_filename) |
| { |
| lib_GLX_filename = libraryLocation(LIBRARY_GL); |
| if (!lib_GLX_filename) |
| Warning("GL/GLX library not found."); |
| } |
| |
| // Load the OpenGL library as necessary |
| |
| if (!lib_GLX && lib_GLX_filename) |
| { |
| Info("Loading GL/GLX from: ",lib_GLX_filename); |
| |
| // We'd rather not use RTLD_GLOBAL, but the Linux Mesa |
| // GL implementation requires this for finding symbols |
| // in libglapi.so.0 |
| |
| lib_GLX = dlopen( lib_GLX_filename, RTLD_LAZY | RTLD_GLOBAL ); |
| } |
| } |
| #endif |
| |
| // Load the entry-point by name, if possible |
| |
| #if REGAL_SYS_ES1 |
| if (Regal::Config::sysES1 && lib_ES1) |
| { |
| void *sym = dlsym(lib_ES1,entry); |
| Internal("Regal::GetProcAddress","loading ",entry," from ",lib_ES1_filename,sym ? " succeeded." : " failed."); |
| if (sym) |
| return sym; |
| } |
| #endif |
| |
| #if REGAL_SYS_ES2 |
| if (Regal::Config::sysES2 && lib_ES2) |
| { |
| void *sym = dlsym(lib_ES2,entry); |
| Internal("Regal::GetProcAddress","loading ",entry," from ",lib_ES2_filename,sym ? " succeeded." : " failed."); |
| if (sym) |
| return sym; |
| } |
| #endif |
| |
| #if REGAL_SYS_GL |
| if (Regal::Config::sysGL && lib_GL) |
| { |
| void *sym = dlsym(lib_GL,entry); |
| Internal("Regal::GetProcAddress","loading ",entry," from ",lib_GL_filename,sym ? " succeeded." : " failed."); |
| return sym; |
| } |
| #endif |
| |
| #if REGAL_SYS_EGL |
| if (Regal::Config::sysEGL && lib_EGL) |
| { |
| void *sym = dlsym(lib_EGL,entry); |
| Internal("Regal::GetProcAddress","loading ",entry," from ",lib_EGL_filename,sym ? " succeeded." : " failed."); |
| if (sym) |
| return sym; |
| } |
| #endif |
| |
| #if REGAL_SYS_GLX |
| if (Regal::Config::sysGLX && lib_GLX) |
| { |
| void *sym = dlsym(lib_GLX,entry); |
| Internal("Regal::GetProcAddress","loading ",entry," from ",lib_GLX_filename,sym ? " succeeded." : " failed."); |
| if (sym) |
| return sym; |
| } |
| #endif |
| |
| #if REGAL_SYS_EGL |
| static PFNEGLGETPROCADDRESSPROC eglGetProcAddress = NULL; |
| |
| if (Regal::Config::sysEGL && lib_EGL) |
| { |
| if (!eglGetProcAddress) |
| eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) dlsym(lib_EGL, "eglGetProcAddress"); |
| |
| if (eglGetProcAddress) |
| { |
| void *sym = (void *) eglGetProcAddress(entry); |
| Internal("Regal::GetProcAddress ","loading ",entry," from eglGetProcAddress",sym ? " succeeded." : " failed."); |
| return sym; |
| } |
| } |
| #endif |
| |
| // Do we need glxGetProcAddress here? |
| |
| #if REGAL_SYS_GLX |
| #endif |
| |
| return NULL; |
| } |
| |
| #elif REGAL_SYS_WGL |
| |
| void *GetProcAddress( const char * entry ) |
| { |
| if (!entry) |
| return NULL; |
| |
| static const char *lib_GL_filename = NULL; |
| if (!lib_GL_filename) |
| lib_GL_filename = libraryLocation(LIBRARY_GL); |
| |
| static HMODULE lib_GL = 0; |
| |
| if (!lib_GL && lib_GL_filename) { |
| Info("Loading OpenGL from ",lib_GL_filename); |
| lib_GL = LoadLibraryA(lib_GL_filename); |
| } |
| |
| static PROC (__stdcall *wglGetProcAddress)(LPCSTR lpszProc); |
| |
| if (lib_GL) |
| { |
| void *sym = ::GetProcAddress( lib_GL, entry ); |
| if (sym) |
| return sym; |
| |
| if (!wglGetProcAddress) |
| wglGetProcAddress = (PROC (__stdcall *)(LPCSTR)) ::GetProcAddress( lib_GL, "wglGetProcAddress"); |
| |
| if (wglGetProcAddress) |
| return wglGetProcAddress(entry); |
| } |
| |
| return NULL; |
| } |
| |
| #endif |
| |
| bool fileExists(const char *filename) |
| { |
| FILE *f = fopen(filename,"r"); |
| if (f) |
| fclose(f); |
| return f!=NULL; |
| } |
| |
| FILE *fileOpen(const char *filename, const char *mode) |
| { |
| // Return NULL for NULL or zero-length filename |
| |
| if (filename && *filename) |
| { |
| if (!strcmp(filename,"stdout")) |
| return stdout; |
| |
| if (!strcmp(filename,"stderr")) |
| return stderr; |
| |
| if (!strcmp(filename,"/dev/null")) |
| return NULL; |
| |
| FILE *f = fopen(filename,mode); |
| if (!f) |
| { |
| string message = print_string("Failed to open ",filename," due to errno ",errno," : ",strerror(errno)); |
| |
| // Helpful advice for Android .apk access to /sdcard |
| |
| #if REGAL_SYS_ANDROID |
| if (errno==EACCES && strstr(filename, "/sdcard/")) |
| message += " - Missing WRITE_EXTERNAL_STORAGE permission in AndroidManifest.xml?"; |
| #endif |
| |
| Warning(message); |
| } |
| return f; |
| } |
| |
| return NULL; |
| } |
| |
| void fileClose(FILE **file) |
| { |
| if (!file || !*file) |
| return; |
| |
| if (*file==stdout) |
| return; |
| |
| if (*file==stderr) |
| return; |
| |
| fclose(*file); |
| *file = NULL; |
| } |
| |
| string makePath(const string &dir, const string &filename) |
| { |
| string tmp(dir); |
| const size_t len = tmp.length(); |
| const char last = len ? tmp[len-1] : '\0'; |
| if (len && last!='/' && last!='\\') |
| tmp += "/"; |
| tmp += filename; |
| return tmp; |
| } |
| |
| string fileRead(FILE *file) |
| { |
| const size_t bufferSize = 4*1024; |
| char *buffer = static_cast<char *>(alloca(bufferSize+1)); |
| string_list<string> tmp; |
| |
| while (true) |
| { |
| size_t bytes = fread(buffer,1,bufferSize,file); |
| buffer[bytes] = '\0'; |
| |
| if (feof(file)) |
| { |
| if (tmp.size()) |
| { |
| tmp.push_back(buffer); |
| return tmp.str(); |
| } |
| else |
| return string(buffer); |
| } |
| else |
| tmp.push_back(buffer); |
| } |
| } |
| |
| // X11 stuff |
| |
| #if REGAL_SYS_X11 |
| |
| // See: |
| // http://tronche.com/gui/x/xlib/window-information/XGetWindowProperty.html |
| // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760470 |
| |
| std::string |
| windowManagerStateDescription(Display *display, Window w) |
| { |
| if (!display || !w) |
| return std::string(); |
| |
| const Atom _NET_WM_STATE = XInternAtom(display,"_NET_WM_STATE",True); |
| Atom type = 0; |
| int format = 0; |
| unsigned long nitems = 0; |
| unsigned long bytes = 0; |
| Atom *list = NULL; |
| |
| if (XGetWindowProperty(display,w,_NET_WM_STATE,0,1024,False,XA_ATOM,&type,&format,&nitems,&bytes,(unsigned char **) &list)==Success) |
| { |
| const Atom _NET_WM_STATE_MODAL = XInternAtom(display,"_NET_WM_STATE_MODAL",True); |
| const Atom _NET_WM_STATE_HIDDEN = XInternAtom(display,"_NET_WM_STATE_HIDDEN",True); |
| const Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(display,"_NET_WM_STATE_FULLSCREEN",True); |
| const Atom _NET_WM_STATE_FOCUSED = XInternAtom(display,"_NET_WM_STATE_FOCUSED",True); |
| |
| string_list<std::string> tmp; |
| |
| for (unsigned long i=0; i<nitems; ++i) |
| { |
| if (_NET_WM_STATE_MODAL !=None && list[i]==_NET_WM_STATE_MODAL ) tmp << "modal"; |
| if (_NET_WM_STATE_HIDDEN !=None && list[i]==_NET_WM_STATE_HIDDEN ) tmp << "hidden"; |
| if (_NET_WM_STATE_FULLSCREEN!=None && list[i]==_NET_WM_STATE_FULLSCREEN) tmp << "fullscreen"; |
| if (_NET_WM_STATE_FOCUSED !=None && list[i]==_NET_WM_STATE_FOCUSED ) tmp << "focused"; |
| } |
| |
| XFree(list); |
| return tmp.join(", "); |
| } |
| |
| return std::string(); |
| } |
| #endif |
| |
| REGAL_NAMESPACE_END |
| |
| |