SDL: x11: Use XcursorLibraryLoadCursor to load system cursors when available. (6f8d6)

From 6f8d6da77f4c8c2ec4502eb72616d7c10e51a9d1 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 16 Feb 2024 02:06:32 -0500
Subject: [PATCH] x11: Use XcursorLibraryLoadCursor to load system cursors when
 available.

Apparently this is necessary on the latest Gnome to get properly themed
cursors, vs ancient X11 standard cursors, as Gnome has dropped the old
theme names that XCreateFontCursor eventually expected to find.

Fixes #8939.

(cherry picked from commit cb9565354c521f3c17122e21bf0918f03407d2b2)
---
 src/video/x11/SDL_x11mouse.c | 31 +++++++++++++++++++++++++++----
 src/video/x11/SDL_x11sym.h   |  1 +
 2 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c
index 6d2a4630492b..04dba64233ae 100644
--- a/src/video/x11/SDL_x11mouse.c
+++ b/src/video/x11/SDL_x11mouse.c
@@ -222,8 +222,9 @@ static SDL_Cursor *X11_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
 
 static SDL_Cursor *X11_CreateSystemCursor(SDL_SystemCursor id)
 {
-    SDL_Cursor *cursor;
-    unsigned int shape;
+    SDL_Cursor *cursor = NULL;
+    unsigned int shape = 0;
+    const char *xcursorname = NULL;
 
     switch (id) {
     default:
@@ -233,47 +234,69 @@ static SDL_Cursor *X11_CreateSystemCursor(SDL_SystemCursor id)
     /*   http://tronche.com/gui/x/xlib/appendix/b/ */
     case SDL_SYSTEM_CURSOR_ARROW:
         shape = XC_left_ptr;
+        xcursorname = "default";
         break;
     case SDL_SYSTEM_CURSOR_IBEAM:
         shape = XC_xterm;
+        xcursorname = "text";
         break;
     case SDL_SYSTEM_CURSOR_WAIT:
         shape = XC_watch;
+        xcursorname = "wait";
         break;
     case SDL_SYSTEM_CURSOR_CROSSHAIR:
         shape = XC_tcross;
+        xcursorname = "crosshair";
         break;
     case SDL_SYSTEM_CURSOR_WAITARROW:
         shape = XC_watch;
+        xcursorname = "progress";
         break;
     case SDL_SYSTEM_CURSOR_SIZENWSE:
         shape = XC_top_left_corner;
+        xcursorname = "nwse-resize";
         break;
     case SDL_SYSTEM_CURSOR_SIZENESW:
         shape = XC_top_right_corner;
+        xcursorname = "nesw-resize";
         break;
     case SDL_SYSTEM_CURSOR_SIZEWE:
         shape = XC_sb_h_double_arrow;
+        xcursorname = "ew-resize";
         break;
     case SDL_SYSTEM_CURSOR_SIZENS:
         shape = XC_sb_v_double_arrow;
+        xcursorname = "ns-resize";
         break;
     case SDL_SYSTEM_CURSOR_SIZEALL:
         shape = XC_fleur;
+        xcursorname = "move";
         break;
     case SDL_SYSTEM_CURSOR_NO:
         shape = XC_pirate;
+        xcursorname = "not-allowed";
         break;
     case SDL_SYSTEM_CURSOR_HAND:
         shape = XC_hand2;
+        xcursorname = "pointer";
         break;
     }
 
     cursor = SDL_calloc(1, sizeof(*cursor));
     if (cursor) {
-        Cursor x11_cursor;
+        Display *dpy = GetDisplay();
+        Cursor x11_cursor = None;
 
-        x11_cursor = X11_XCreateFontCursor(GetDisplay(), shape);
+#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
+        SDL_assert(xcursorname != NULL);
+        if (SDL_X11_HAVE_XCURSOR) {
+            x11_cursor = X11_XcursorLibraryLoadCursor(dpy, xcursorname);
+        }
+#endif
+
+        if (x11_cursor == None) {
+            x11_cursor = X11_XCreateFontCursor(dpy, shape);
+        }
 
         cursor->driverdata = (void *)(uintptr_t)x11_cursor;
     } else {
diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h
index 9de95e45932e..450c07ebf2e9 100644
--- a/src/video/x11/SDL_x11sym.h
+++ b/src/video/x11/SDL_x11sym.h
@@ -253,6 +253,7 @@ SDL_X11_MODULE(XCURSOR)
 SDL_X11_SYM(XcursorImage*,XcursorImageCreate,(int a,int b),(a,b),return)
 SDL_X11_SYM(void,XcursorImageDestroy,(XcursorImage *a),(a),)
 SDL_X11_SYM(Cursor,XcursorImageLoadCursor,(Display *a,const XcursorImage *b),(a,b),return)
+SDL_X11_SYM(Cursor,XcursorLibraryLoadCursor,(Display *a, const char *b),(a,b),return)
 #endif
 
 /* Xdbe support */