From 88f591f389ba4ac13dd5aebfffa7863805758bcb Mon Sep 17 00:00:00 2001
From: Po Lu <luangruo@yahoo.com>
Date: Sat, 19 Feb 2022 20:05:18 +0800
Subject: [PATCH] Improve portability of alpha channel visual detection

* src/xfns.c (select_visual): Look for PictVisuals with an alpha
channel instead of blindly assuming that 32 bit visuals have an
alpha channel.
(Fx_show_tip): Fix crash on some displays where child is None.

* src/xterm.c (x_term_init): Initialize Xrender before
calling select_visual.
---
 src/xfns.c  | 52 +++++++++++++++++++++++++++++++++++-----------------
 src/xterm.c | 31 ++++++++++++++++++-------------
 2 files changed, 53 insertions(+), 30 deletions(-)

diff --git a/src/xfns.c b/src/xfns.c
index 0a8d18d9187..b0e7af9d8fa 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6574,28 +6574,45 @@ select_visual (struct x_display_info *dpyinfo)
 
       vinfo_template.screen = XScreenNumberOfScreen (screen);
 
-#if !defined USE_X_TOOLKIT && !(defined USE_GTK && !defined HAVE_GTK3)
-      /* First attempt to use 32-bit visual if available */
-
-      vinfo_template.depth = 32;
-      vinfo_template.class = TrueColor;
+#if !defined USE_X_TOOLKIT && !(defined USE_GTK && !defined HAVE_GTK3) \
+  && defined HAVE_XRENDER
+      int i;
+      XRenderPictFormat *format;
 
-      vinfo = XGetVisualInfo (dpy, (VisualScreenMask
-				    | VisualDepthMask
-				    | VisualClassMask),
-			      &vinfo_template, &n_visuals);
+      /* First attempt to find a visual with an alpha mask if
+	 available.  That information is only available when the
+	 render extension is present, and we cannot do much with such
+	 a visual if it isn't.  */
 
-      if (n_visuals > 0 && vinfo)
+      if (dpyinfo->xrender_supported_p)
 	{
-	  dpyinfo->n_planes = vinfo->depth;
-	  dpyinfo->visual = vinfo->visual;
-	  XFree (vinfo);
-	  return;
-	}
 
+	  vinfo = XGetVisualInfo (dpy, VisualScreenMask,
+				  &vinfo_template, &n_visuals);
+
+	  for (i = 0; i < n_visuals; ++i)
+	    {
+	      format = XRenderFindVisualFormat (dpy, vinfo[i].visual);
+
+	      if (format && format->type == PictTypeDirect
+		  && format->direct.alphaMask)
+		{
+		  dpyinfo->n_planes = vinfo[i].depth;
+		  dpyinfo->visual = vinfo[i].visual;
+		  dpyinfo->pict_format = format;
+
+		  XFree (vinfo);
+		  return;
+		}
+	    }
+
+	  if (vinfo)
+	    XFree (vinfo);
+	}
 #endif /* !USE_X_TOOLKIT */
 
-      /* 32-bit visual not available, fallback to default visual */
+      /* Visual with alpha channel (or the Render extension) not
+	 available, fallback to default visual.  */
       dpyinfo->visual = DefaultVisualOfScreen (screen);
       vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
       vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
@@ -8091,7 +8108,8 @@ Text larger than the specified size is clipped.  */)
 			     FRAME_DISPLAY_INFO (f)->root_window,
 			     FRAME_DISPLAY_INFO (f)->root_window,
 			     root_x, root_y, &dest_x_return,
-			     &dest_y_return, &child))
+			     &dest_y_return, &child)
+      && child != None)
     {
       /* But only if the child is not override-redirect, which can
 	 happen if the pointer is above a menu.  */
diff --git a/src/xterm.c b/src/xterm.c
index 2dc420a8dee..e2ad0b48f58 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -15989,6 +15989,18 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
 #else
   dpyinfo->display->db = xrdb;
 #endif
+
+#ifdef HAVE_XRENDER
+  int event_base, error_base;
+  dpyinfo->xrender_supported_p
+    = XRenderQueryExtension (dpyinfo->display, &event_base, &error_base);
+
+  if (dpyinfo->xrender_supported_p)
+    dpyinfo->xrender_supported_p
+      = XRenderQueryVersion (dpyinfo->display, &dpyinfo->xrender_major,
+			     &dpyinfo->xrender_minor);
+#endif
+
   /* Put the rdb where we can find it in a way that works on
      all versions.  */
   dpyinfo->rdb = xrdb;
@@ -16004,19 +16016,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
   reset_mouse_highlight (&dpyinfo->mouse_highlight);
 
 #ifdef HAVE_XRENDER
-  int event_base, error_base;
-  dpyinfo->xrender_supported_p
-    = XRenderQueryExtension (dpyinfo->display, &event_base, &error_base);
-
-  if (dpyinfo->xrender_supported_p)
-    {
-      if (!XRenderQueryVersion (dpyinfo->display, &dpyinfo->xrender_major,
-				&dpyinfo->xrender_minor))
-	dpyinfo->xrender_supported_p = false;
-      else
-	dpyinfo->pict_format = XRenderFindVisualFormat (dpyinfo->display,
-							dpyinfo->visual);
-    }
+  if (dpyinfo->xrender_supported_p
+      /* This could already have been initialized by
+	 `select_visual'.  */
+      && !dpyinfo->pict_format)
+    dpyinfo->pict_format = XRenderFindVisualFormat (dpyinfo->display,
+						    dpyinfo->visual);
 #endif
 
 #ifdef HAVE_XSYNC
-- 
2.39.5