SDL: SDL3: SDL_render_gl(render name: opengl) dose not support transparent on Linux/X11 (Bug #11273) (#11274)

From e0321ca5b6cb70ce178e533884b407571d2d1002 Mon Sep 17 00:00:00 2001
From: rhett-lee <[EMAIL REDACTED]>
Date: Sun, 20 Oct 2024 11:21:50 +0800
Subject: [PATCH] SDL3: SDL_render_gl(render name: opengl) dose not support
 transparent on Linux/X11 (Bug #11273) (#11274)

SDL3: SDL_render_gl(render name: opengl) dose not support transparent on Linux/X11:

Create SDL window with SDL_WINDOW_TRANSPARENT flag;
Create "opengl" renderer for the window;
The window can't shown with errors:
X Error of failed request: BadMatch (invalid parameter attributes)
Major opcode of failed request: 130 (MIT-SHM)
Minor opcode of failed request: 3 (X_ShmPutImage)
Bug reason:
SDL_x11window.c:490 : bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
SDL_x11window.c:566 : vinfo = X11_GL_GetVisual(_this, display, screen, transparent);[XVisualInfo *vinfo]
the X11_GL_GetVisual function returns a vinfo dose not support transparent.

Fix:
SDL_x11opengl.c:637 : XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, bool transparent)
X11_GL_GetVisual should returns a vinfo support transparent when transparent is true.
---
 src/video/x11/SDL_x11opengl.c | 58 +++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c
index 7eb6f467e043d..888c4892421c7 100644
--- a/src/video/x11/SDL_x11opengl.c
+++ b/src/video/x11/SDL_x11opengl.c
@@ -608,6 +608,32 @@ static int X11_GL_GetAttributes(SDL_VideoDevice *_this, Display *display, int sc
     return i;
 }
 
+//get the first transparent Visual
+static XVisualInfo* X11_GL_GetTransparentVisualInfo(Display *display, int screen)
+{
+    XVisualInfo* visualinfo = NULL;
+    XVisualInfo vi_in;
+    int out_count = 0;
+
+    vi_in.screen = screen;
+    visualinfo = X11_XGetVisualInfo(display, VisualScreenMask, &vi_in, &out_count);
+    if (visualinfo != NULL) {
+        int i = 0;
+        for (i = 0; i < out_count; i++) {
+            XVisualInfo* v = &visualinfo[i];
+            Uint32 format = X11_GetPixelFormatFromVisualInfo(display, v);
+            if (SDL_ISPIXELFORMAT_ALPHA(format)) {
+                vi_in.screen = screen;
+                vi_in.visualid = v->visualid;
+                X11_XFree(visualinfo);
+                visualinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &vi_in, &out_count);
+                break;
+            }
+        }
+    }
+    return visualinfo;
+}
+
 XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, bool transparent)
 {
     // 64 seems nice.
@@ -666,6 +692,18 @@ XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int scre
         }
     }
 
+    if (transparent && vinfo) {
+        Uint32 format = X11_GetPixelFormatFromVisualInfo(display, vinfo);
+        if (!SDL_ISPIXELFORMAT_ALPHA(format)) {
+            // not transparent!
+            XVisualInfo* visualinfo = X11_GL_GetTransparentVisualInfo(display, screen);
+            if (visualinfo != NULL) {
+                X11_XFree(vinfo);
+                vinfo = visualinfo;
+            }
+        }
+    }
+
     if (!vinfo) {
         SDL_SetError("Couldn't find matching GLX visual");
     }
@@ -814,6 +852,26 @@ SDL_GLContext X11_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
                                                                                &fbcount);
                     }
 
+                    if (transparent && (framebuffer_config != NULL)) {
+                        int i;
+                        for (i = 0; i < fbcount; i++) {
+                            XVisualInfo* vinfo_temp = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[i]);
+                            if ( vinfo_temp != NULL) {
+                                Uint32 format = X11_GetPixelFormatFromVisualInfo(display, vinfo_temp);
+                                if (SDL_ISPIXELFORMAT_ALPHA(format)) {
+                                    // found!
+                                    context = (SDL_GLContext)_this->gl_data->glXCreateContextAttribsARB(display,
+                                                                                                        framebuffer_config[i],
+                                                                                                        share_context, True, attribs);
+                                    X11_XFree(framebuffer_config);
+                                    framebuffer_config = NULL;
+                                    X11_XFree(vinfo_temp);
+                                    break;
+                                }
+                                X11_XFree(vinfo_temp);
+                            }
+                        }
+                    }
                     if (framebuffer_config) {
                         context = (SDL_GLContext)_this->gl_data->glXCreateContextAttribsARB(display,
                                                                              framebuffer_config[0],