From 1826e23c29b7126e3e212a83d28a8032921fdc6d Mon Sep 17 00:00:00 2001 From: Linus Dierheimer Date: Sat, 4 Jun 2022 15:21:34 +0200 Subject: [PATCH] OpenGL module --- .github/workflows/pull_request.yml | 2 +- .github/workflows/push.yml | 2 +- CMakeLists.txt | 51 ++++- README.md | 3 + completions/bash | 4 + presets/all | 2 +- src/common/init.c | 15 ++ src/data/config.txt | 11 + src/data/help.txt | 6 + src/data/modules.txt | 1 + src/detection/vulkan.c | 2 + src/fastfetch.c | 40 ++++ src/fastfetch.h | 14 ++ src/modules/opengl.c | 319 +++++++++++++++++++++++++++++ 14 files changed, 468 insertions(+), 4 deletions(-) create mode 100644 src/modules/opengl.c diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 584849735..370e6b323 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v2 - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev + run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libgl-dev libegl-dev libglx-dev - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 745e8b176..74d8a2071 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -16,7 +16,7 @@ jobs: uses: actions/checkout@v2 - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev + run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libgl-dev libegl-dev libglx-dev - name: Initialize CodeQL uses: github/codeql-action/init@v1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f347e63..2938e30f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,9 @@ OPTION(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON) OPTION(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON) OPTION(ENABLE_ZLIB "Enable zlib" ON) OPTION(ENABLE_CHAFA "Enable chafa" ON) +OPTION(ENABLE_GL "Enable gl" ON) +OPTION(ENABLE_EGL "Enable egl" ON) +OPTION(ENABLE_GLX "Enable glx" ON) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -168,6 +171,7 @@ add_library(libfastfetch STATIC src/modules/date.c src/modules/time.c src/modules/colors.c + src/modules/opengl.c ) if(ENABLE_LIBPCI) @@ -343,7 +347,48 @@ if(ENABLE_CHAFA) message(WARNING "Package chafa>=1.10 not found. Building without support.") endif() else() - message(WARNING "Chafa not enabled, because neither ImageMagick6 nor ImageMagick7 is found. Building without support.") + message(WARNING "Chafa not enabled, because neither ImageMagick6 nor ImageMagick7 were found. Building without support.") + endif() +endif() + +if(ENABLE_GL) + pkg_check_modules(GL gl) + if(NOT GL_FOUND) + message(WARNING "Package gl not found. Building without support.") + endif() +endif() + +if(ENABLE_EGL) + if(GL_FOUND) + pkg_check_modules(EGL egl) + if(EGL_FOUND) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EGL=1) + else() + message(WARNING "Package egl not found. Building without support.") + endif() + else() + message(WARNING "egl not enabled, because gl was not enabled or found. Building without support.") + endif() +endif() + +if(ENABLE_GLX) + if(GL_FOUND) + pkg_check_modules(GLX glx) + if(GLX_FOUND) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GLX=1) + else() + message(WARNING "Package glx not found. Building without support.") + endif() + else() + message(WARNING "glx not enabled, because gl was not enabled or found. Building without support") + endif() +endif() + +if(GL_FOUND) + if(EGL_FOUND OR GLX_FOUND) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GL=1) + else() + message(WARNING "gl not enabled, because neither egl nor glx were found. Building without support.") endif() endif() @@ -368,6 +413,10 @@ target_include_directories(libfastfetch PRIVATE ${IMAGEMAGICK6_INCLUDE_DIRS} PRIVATE ${ZLIB_INCLUDE_DIRS} PRIVATE ${CHAFA_INCLUDE_DIRS} + PRIVATE ${VULKAN_INCLUDE_DIRS} + PRIVATE ${GL_INCLUDE_DIRS} + PRIVATE ${EGL_INCLUDE_DIRS} + PRIVATE ${GLX_INCLUDE_DIRS} ) target_link_libraries(libfastfetch diff --git a/README.md b/README.md index 33b8363be..de3364920 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,9 @@ The following libraries are used if present at runtime: * [`libchafa`](https://github.com/hpjansson/chafa): Image output as ascii art. * [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol. * [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song. +* [`libGL`](https://dri.freedesktop.org/wiki/libGL/):OpenGL module. At least one context creation library must be present too. +* [`libEGL`](https://www.khronos.org/registry/EGL/): OpenGL module, using EGL context. +* [`libGLX`](https://dri.freedesktop.org/wiki/GLX/): OpenGL module, using GLX context. * [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font. * [`libsqlite3`](https://www.sqlite.org/index.html): Needed for rpm package count. * [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE. diff --git a/completions/bash b/completions/bash index 916e84dc1..7c03e8eb3 100644 --- a/completions/bash +++ b/completions/bash @@ -217,6 +217,7 @@ __fastfetch_completion() "--date-key" "--time-format" "--time-key" + "--gl" ) local FF_OPTIONS_PATH=( @@ -237,6 +238,9 @@ __fastfetch_completion() "--lib-imagemagick" "--lib-z" "--lib-chafa" + "--lib-gl" + "--lib-egl" + "--lib-glx" "--battery-dir" "--load-config" ) diff --git a/presets/all b/presets/all index 08094c54d..dac0b9c1b 100644 --- a/presets/all +++ b/presets/all @@ -1 +1 @@ ---structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:Break:Colors +--structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:OpenGL:Break:Colors diff --git a/src/common/init.c b/src/common/init.c index fc6d3d04c..105cee343 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -125,6 +125,7 @@ static void defaultConfig(FFinstance* instance) instance->config.disableLinewrap = true; instance->config.hideCursor = true; instance->config.escapeBedrock = true; + instance->config.glType = FF_GL_TYPE_AUTO; ffStrbufInitA(&instance->config.osFormat, 0); ffStrbufInitA(&instance->config.osKey, 0); @@ -190,6 +191,8 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.timeFormat, 0); ffStrbufInitA(&instance->config.vulkanKey, 0); ffStrbufInitA(&instance->config.vulkanFormat, 0); + ffStrbufInitA(&instance->config.openGLKey, 0); + ffStrbufInitA(&instance->config.openGLFormat, 0); ffStrbufInitA(&instance->config.libPCI, 0); ffStrbufInitA(&instance->config.libVulkan, 0); @@ -207,6 +210,9 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.libImageMagick, 0); ffStrbufInitA(&instance->config.libZ, 0); ffStrbufInitA(&instance->config.libChafa, 0); + ffStrbufInitA(&instance->config.libGL, 0); + ffStrbufInitA(&instance->config.libEGL, 0); + ffStrbufInitA(&instance->config.libGLX, 0); ffStrbufInitA(&instance->config.diskFolders, 0); @@ -338,6 +344,15 @@ void ffListFeatures() #ifdef FF_HAVE_RPM "rpm\n" #endif + #ifdef FF_HAVE_GL + "gl\n" + #endif + #ifdef FF_HAVE_EGL + "egl\n" + #endif + #ifdef FF_HAVE_GLX + "glx\n" + #endif "" , stdout); } diff --git a/src/data/config.txt b/src/data/config.txt index 2126c621d..29e308678 100644 --- a/src/data/config.txt +++ b/src/data/config.txt @@ -157,6 +157,12 @@ # Default is true. #--escape-bedrock true +# GL option +# Sets with opengl context creation library to use +# Must be either auto, egl or glx +# Default is auto. +#--gl auto + # Key options: # Sets the displayed key of a module # Can be any string. Some of theme take an argument like a format string. See "fastfetch --help format" for help. @@ -190,6 +196,7 @@ #--song-key Song #--datetime-key Date Time #--vulkan-key Vulkan +#--opengl-key OpenGL # Format options: # Sets the format string for module values. @@ -226,6 +233,7 @@ #--song-format #--datetime-format #--vulkan-format +#--opengl-format # Library options: # Sets an user specific path to a library to load. @@ -246,3 +254,6 @@ #--lib-imagemagick /usr/lib/libMagickCore-7.Q16HDRI.so #--lib-z /usr/lib/libz.so #--lib-chafa /usr/lib/libchafa.so +#--lib-gl /usr/lib/libGL.so +#--lib-egl /usr/lib/libEGL.so +#--lib-GLX /usr/lib/libGLX.so diff --git a/src/data/help.txt b/src/data/help.txt index a2aad9825..893b8ba2b 100644 --- a/src/data/help.txt +++ b/src/data/help.txt @@ -78,6 +78,7 @@ Format options: Provide the format string for custom output. Use fastfetch --hel --time-format --date-format --vulkan-format + --opengl-format Key options: Provide a custom key for an output --os-key @@ -112,6 +113,7 @@ Key options: Provide a custom key for an output --time-key --date-key --vulkan-key + --opengl-key Library options: Set the path of a library to load --lib-PCI @@ -130,6 +132,9 @@ Library options: Set the path of a library to load --lib-imagemagick --lib-z --lib-chafa + --lib-gl + --lib-egl + --lib-glx Module specific options: --separator-string : Set the string printed by the separator module @@ -141,6 +146,7 @@ Module specific options: --localip-show-loop : Show loop back addresses (127.0.0.1) in local ip module. Default is false --public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0) --player-name: The name of the player to use + --gl : Sets the opengl context creation library to use. Must be auto, egl, or glx. Default is auto Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci" If a value starts with a ?, it is optional. "true" will be used if not set. diff --git a/src/data/modules.txt b/src/data/modules.txt index f2dcdcbb0..80073f7d9 100644 --- a/src/data/modules.txt +++ b/src/data/modules.txt @@ -17,6 +17,7 @@ Locale LocalIP Memory OS +OpenGL Packages Player Processes diff --git a/src/detection/vulkan.c b/src/detection/vulkan.c index 2c985d801..d6dae7e01 100644 --- a/src/detection/vulkan.c +++ b/src/detection/vulkan.c @@ -216,6 +216,8 @@ const FFVulkanResult* ffDetectVulkan(const FFinstance* instance) #ifdef FF_HAVE_VULKAN detectVulkan(instance, &result); + #else + FF_UNUSED(instance); #endif pthread_mutex_unlock(&mutex); diff --git a/src/fastfetch.c b/src/fastfetch.c index 607b14afc..187525fb6 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -353,6 +353,14 @@ static inline void printCommandHelp(const char* command) "Conformance version" ); } + else if(strcasecmp(command, "opengl-format") == 0) + { + constructAndPrintCommandHelpFormat("opengl", "{}", 3, + "version", + "renderer", + "vendor" + ); + } else fprintf(stderr, "No specific help for command %s provided\n", command); } @@ -980,6 +988,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.vulkanKey); else if(strcasecmp(key, "--vulkan-format") == 0) optionParseString(key, value, &instance->config.vulkanFormat); + else if(strcasecmp(key, "--opengl-key") == 0) + optionParseString(key, value, &instance->config.openGLKey); + else if(strcasecmp(key, "--opengl-format") == 0) + optionParseString(key, value, &instance->config.openGLFormat); /////////////////// //Library options// @@ -1017,6 +1029,12 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.libZ); else if(strcasecmp(key, "--lib-chafa") == 0) optionParseString(key, value, &instance->config.libChafa); + else if(strcasecmp(key, "--lib-gl") == 0) + optionParseString(key, value, &instance->config.libGL); + else if(strcasecmp(key, "--lib-egl") == 0) + optionParseString(key, value, &instance->config.libEGL); + else if(strcasecmp(key, "--lib-glx") == 0) + optionParseString(key, value, &instance->config.libGLX); ////////////////// //Module options// @@ -1040,6 +1058,26 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.playerName); else if(strcasecmp(key, "--public-ip-timeout") == 0) instance->config.publicIpTimeout = optionParseUInt32(key, value); + else if(strcasecmp(key, "--gl") == 0) + { + if(value == NULL) + { + fprintf(stderr, "Error: usage: %s \n", key); + exit(491); + } + + if(strcasecmp(value, "auto") == 0) + instance->config.glType = FF_GL_TYPE_AUTO; + else if(strcasecmp(value, "egl") == 0) + instance->config.glType = FF_GL_TYPE_EGL; + else if(strcasecmp(value, "glx") == 0) + instance->config.glType = FF_GL_TYPE_GLX; + else + { + fprintf(stderr, "Error: unknown gl type: %s\n", value); + exit(492); + } + } ////////////////// //Unknown option// @@ -1183,6 +1221,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char ffPrintColors(instance); else if(strcasecmp(line, "vulkan") == 0) ffPrintVulkan(instance); + else if(strcasecmp(line, "opengl") == 0) + ffPrintOpenGL(instance); else ffPrintError(instance, line, 0, NULL, NULL, 0, ""); } diff --git a/src/fastfetch.h b/src/fastfetch.h index 76797ec93..d1147d21f 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -42,6 +42,13 @@ typedef enum FFLogoType FF_LOGO_TYPE_CHAFA //Image file, printed as ascii art using libchafa } FFLogoType; +typedef enum FFGLType +{ + FF_GL_TYPE_AUTO, + FF_GL_TYPE_EGL, + FF_GL_TYPE_GLX +} FFGLType; + typedef struct FFconfig { FFstrbuf logoSource; @@ -63,6 +70,7 @@ typedef struct FFconfig bool disableLinewrap; bool hideCursor; bool escapeBedrock; + FFGLType glType; FFstrbuf osFormat; FFstrbuf osKey; @@ -128,6 +136,8 @@ typedef struct FFconfig FFstrbuf timeFormat; FFstrbuf vulkanKey; FFstrbuf vulkanFormat; + FFstrbuf openGLKey; + FFstrbuf openGLFormat; FFstrbuf libPCI; FFstrbuf libVulkan; @@ -145,6 +155,9 @@ typedef struct FFconfig FFstrbuf libImageMagick; FFstrbuf libZ; FFstrbuf libChafa; + FFstrbuf libGL; + FFstrbuf libEGL; + FFstrbuf libGLX; FFstrbuf diskFolders; @@ -597,5 +610,6 @@ void ffPrintLocalIp(FFinstance* instance); void ffPrintPublicIp(FFinstance* instance); void ffPrintColors(FFinstance* instance); void ffPrintVulkan(FFinstance* instance); +void ffPrintOpenGL(FFinstance* instance); #endif diff --git a/src/modules/opengl.c b/src/modules/opengl.c new file mode 100644 index 000000000..6d1c36f5a --- /dev/null +++ b/src/modules/opengl.c @@ -0,0 +1,319 @@ +#include "fastfetch.h" + +#include + +#define FF_OPENGL_MODULE_NAME "OpenGL" +#define FF_OPENGL_NUM_FORMAT_ARGS 3 + +#ifdef FF_HAVE_GL +#include + +typedef struct GLData +{ + FF_LIBRARY_SYMBOL(glGetString); +} GLData; + +static const char* glHandlePrint(FFinstance* instance, const GLData* data) +{ + const char* version = (const char*) data->ffglGetString(GL_VERSION); + if(!ffStrSet(version)) + return "glGetString(GL_VERSION) returned NULL"; + + const char* renderer = (const char*) data->ffglGetString(GL_RENDERER); + const char* vendor = (const char*) data->ffglGetString(GL_VENDOR); + + if(instance->config.openGLFormat.length == 0) + { + ffPrintLogoAndKey(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGLKey); + puts(version); + } + else + { + ffPrintFormatString(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGLKey, &instance->config.openGLFormat, NULL, FF_OPENGL_NUM_FORMAT_ARGS, (FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_STRING, version}, + {FF_FORMAT_ARG_TYPE_STRING, renderer}, + {FF_FORMAT_ARG_TYPE_STRING, vendor} + }); + } + + return NULL; +} + +#ifdef FF_HAVE_EGL +#include + +typedef struct EGLData +{ + GLData* glData; + + FF_LIBRARY_SYMBOL(eglGetDisplay); + FF_LIBRARY_SYMBOL(eglInitialize); + FF_LIBRARY_SYMBOL(eglBindAPI); + FF_LIBRARY_SYMBOL(eglGetConfigs); + FF_LIBRARY_SYMBOL(eglCreatePbufferSurface); + FF_LIBRARY_SYMBOL(eglCreateContext); + FF_LIBRARY_SYMBOL(eglMakeCurrent); + FF_LIBRARY_SYMBOL(eglDestroyContext); + FF_LIBRARY_SYMBOL(eglDestroySurface); + FF_LIBRARY_SYMBOL(eglTerminate); + + EGLDisplay display; + EGLConfig config; + EGLSurface surface; + EGLContext context; +} EGLData; + +static const char* eglHandleContext(FFinstance* instance, EGLData* data) +{ + if(data->ffeglMakeCurrent(data->display, data->surface, data->surface, data->context) != EGL_TRUE) + return "eglMakeCurrent returned EGL_FALSE"; + + return glHandlePrint(instance, data->glData); +} + +static const char* eglHandleSurface(FFinstance* instance, EGLData* data) +{ + data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE}); + if(data->context == EGL_NO_CONTEXT) + return "eglCreateContext returned EGL_NO_CONTEXT"; + + const char* error = eglHandleContext(instance, data); + data->ffeglDestroyContext(data->display, data->context); + return error; +} + +static const char* eglHandleDisplay(FFinstance* instance, EGLData* data) +{ + if(data->ffeglBindAPI(EGL_OPENGL_API) != EGL_TRUE) + return "eglBindAPI returned EGL_FALSE"; + + EGLint eglConfigCount; + data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount); + if(eglConfigCount == 0) + return "eglGetConfigs returned 0 configs"; + + data->surface = data->ffeglCreatePbufferSurface(data->display, data->config, (EGLint[]){ + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE + }); + + if(data->surface == EGL_NO_SURFACE) + return "eglCreatePbufferSurface returned EGL_NO_SURFACE"; + + const char* error = eglHandleSurface(instance, data); + data->ffeglDestroySurface(data->display, data->surface); + return error; +} + +static const char* eglHandleData(FFinstance* instance, EGLData* data) +{ + data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY); + if(data->display == EGL_NO_DISPLAY) + return "eglGetDisplay returned EGL_NO_DISPLAY"; + + EGLint major, minor; + if(data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE) + return "eglInitialize returned EGL_FALSE"; + + const char* error = eglHandleDisplay(instance, data); + data->ffeglTerminate(data->display); + return error; +} + +static const char* eglPrint(FFinstance* instance, GLData* glData) +{ + EGLData eglData; + eglData.glData = glData; + + FF_LIBRARY_LOAD(egl, instance->config.libEGL, "dlopen egl failed", "libEGL.so", 1); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglGetDisplay, eglGetDisplay, "dlsym eglGetDisplay failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglInitialize, eglInitialize, "dlsym eglInitialize failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglBindAPI, eglBindAPI, "dlsym eglBindAPI failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglGetConfigs, eglGetConfigs, "dlsym eglGetConfigs failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglCreatePbufferSurface, eglCreatePbufferSurface, "dlsym eglCreatePbufferSurface failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglCreateContext, eglCreateContext, "dlsym eglCreateContext failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglMakeCurrent, eglMakeCurrent, "dlsym eglMakeCurrent failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglDestroyContext, eglDestroyContext, "dlsym eglDestroyContext failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglDestroySurface, eglDestroySurface, "dlsym eglDestroySurface failed"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglTerminate, eglTerminate, "dlsym eglTerminate failed"); + + const char* error = eglHandleData(instance, &eglData); + dlclose(egl); + return error; +} + +#endif //FF_HAVE_EGL + +#ifdef FF_HAVE_GLX +#include + +typedef struct GLXData +{ + GLData* glData; + + FF_LIBRARY_SYMBOL(XOpenDisplay); + FF_LIBRARY_SYMBOL(glXChooseVisual); + FF_LIBRARY_SYMBOL(XCreatePixmap); + FF_LIBRARY_SYMBOL(glXCreateGLXPixmap); + FF_LIBRARY_SYMBOL(glXCreateContext); + FF_LIBRARY_SYMBOL(glXMakeCurrent); + FF_LIBRARY_SYMBOL(glXDestroyContext); + FF_LIBRARY_SYMBOL(glXDestroyGLXPixmap); + FF_LIBRARY_SYMBOL(XFreePixmap); + FF_LIBRARY_SYMBOL(XCloseDisplay); + + Display* display; + XVisualInfo* visualInfo; + Pixmap pixmap; + GLXPixmap glxPixmap; + GLXContext context; +} GLXData; + +static const char* glxHandleContext(FFinstance* instance, GLXData* data) +{ + if(data->ffglXMakeCurrent(data->display, data->glxPixmap, data->context) != True) + return "glXMakeCurrent returned False"; + + return glHandlePrint(instance, data->glData); +} + +static const char* glxHandleGLXPixmap(FFinstance* instance, GLXData* data) +{ + data->context = data->ffglXCreateContext(data->display, data->visualInfo, NULL, True); + if(data->context == NULL) + return "glXCreateContext returned NULL"; + + const char* error = glxHandleContext(instance, data); + data->ffglXDestroyContext(data->display, data->context); + return error; +} + +static const char* glxHandlePixmap(FFinstance* instance, GLXData* data) +{ + data->glxPixmap = data->ffglXCreateGLXPixmap(data->display, data->visualInfo, data->pixmap); + if(data->glxPixmap == None) + return "glXCreateGLXPixmap returned None"; + + const char* error = glxHandleGLXPixmap(instance, data); + data->ffglXDestroyGLXPixmap(data->display, data->glxPixmap); + return error; +} + +static const char* glxHandleVisualInfo(FFinstance* instance, GLXData* data) +{ + data->pixmap = data->ffXCreatePixmap(data->display, DefaultRootWindow(data->display), 1, 1, (unsigned int) data->visualInfo->depth); + if(data->pixmap == None) + return "XCreatePixmap returned None"; + + const char* error = glxHandlePixmap(instance, data); + data->ffXFreePixmap(data->display, data->pixmap); + return error; +} + +static const char* glxHandleDisplay(FFinstance* instance, GLXData* data) +{ + data->visualInfo = data->ffglXChooseVisual(data->display, DefaultScreen(data->display), (int[]){None}); + if(data->visualInfo == NULL) + return "glXChooseVisual returned NULL"; + + return glxHandleVisualInfo(instance, data); +} + +static const char* glxHandleData(FFinstance* instance, GLXData* data) +{ + data->display = data->ffXOpenDisplay(NULL); + if(data->display == NULL) + return "XOpenDisplay returned NULL"; + + const char* error = glxHandleDisplay(instance, data); + data->ffXCloseDisplay(data->display); + return error; +} + +static const char* glxPrint(FFinstance* instance, GLData* glData) +{ + GLXData data; + data.glData = glData; + + FF_LIBRARY_LOAD(glx, instance->config.libGLX, "dlopen glx failed", "libGLX.so", 1); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXOpenDisplay, XOpenDisplay, "dlsym XOpenDisplay returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXChooseVisual, glXChooseVisual, "dlsym glXChooseVisual returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXCreatePixmap, XCreatePixmap, "dlsym XCreatePixmap returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXCreateGLXPixmap, glXCreateGLXPixmap, "dlsym glXCreateGLXPixmap returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXCreateContext, glXCreateContext, "dlsym glXCreateContext returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXMakeCurrent, glXMakeCurrent, "dlsym glXMakeCurrent returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXDestroyContext, glXDestroyContext, "dlsym glXDestroyContext returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXDestroyGLXPixmap, glXDestroyGLXPixmap, "dlsym glXDestroyGLXPixmap returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXFreePixmap, XFreePixmap, "dlsym XFreePixmap returned NULL"); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXCloseDisplay, XCloseDisplay, "dlsym XCloseDisplay returned NULL"); + + const char* error = glxHandleData(instance, &data); + dlclose(glx); + return error; +} + +#endif //FF_HAVE_GLX + +static const char* glHandleGL(FFinstance* instance, GLData* data) +{ + if(instance->config.glType == FF_GL_TYPE_GLX) + { + #ifdef FF_HAVE_GL + return glxPrint(instance, data); + #else + return = "fastfetch was compiled without glx support"; + #endif + } + + if(instance->config.glType == FF_GL_TYPE_EGL) + { + #ifdef FF_HAVE_EGL + return eglPrint(instance, data); + #else + return "fastfetch was compiled without egl support"; + #endif + } + + const char* error = ""; // not NULL dummy value + + #ifdef FF_HAVE_EGL + error = eglPrint(instance, data); + #endif + + #ifdef FF_HAVE_GLX + if(error != NULL) + error = glxPrint(instance, data); + #endif + + return error; +} + +static const char* glPrint(FFinstance* instance) +{ + GLData data; + + FF_LIBRARY_LOAD(gl, instance->config.libGL, "dlopen gl failed", "libGL.so", 1); + FF_LIBRARY_LOAD_SYMBOL_ADRESS(gl, data.ffglGetString, glGetString, "dlsym glGetString failed"); + + const char* error = glHandleGL(instance, &data); + + dlclose(gl); + return error; +} + +#endif //FF_HAVE_GL + +void ffPrintOpenGL(FFinstance* instance) +{ + const char* error; + + #ifndef FF_HAVE_GL + error = "Fastfetch was built without gl support."; + #else + error = glPrint(instance); + #endif + + if(error != NULL) + ffPrintError(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGLKey, &instance->config.openGLFormat, FF_OPENGL_NUM_FORMAT_ARGS, error); +}