Subject: bug#76761: 31.0.50; Image icons from 'icons.el' could be accidentally dropped

From: Eli Zaretskii <[email-masked]>
Date: Thu, 06 Mar 2025 11:48:14 +0200

> Cc: [email-masked]
> Date: Wed, 05 Mar 2025 15:47:56 +0200
> From: Eli Zaretskii <[email-masked]>
> 
> > From: Pengji Zhang <[email-masked]>
> > Date: Wed, 05 Mar 2025 18:10:38 +0800
> > 
> > Currently in 'icons.el' image icons returned by 'icon-string' is a space
> > with a display property (see 'icons--create'). However, IMO it is common
> > to stripped spaces, and that means the icon could be accidentally
> > removed. For example,
> > 
> >   - Run 'emacs -Q'
> >   - Evaluate the following snippet:
> > 
> > --8<---------------cut here---------------start------------->8---
> > (require 'outline) ; for the icon
> > (setopt mode-line-compact t)
> > (setf global-mode-string
> >       '("" (:eval (icon-string 'outline-open)) " "))
> > (force-mode-line-update t)
> > --8<---------------cut here---------------end--------------->8---
> > 
> > Notice that the down arrow icon does not show at all in the mode line
> > due to 'mode-line-compact'.
> > 
> > I suppose an easy fix is to use a non-space character. WDYT?
> 
> Isn't that rather a bug in mode-line-compact?  It shouldn't remove
> spaces which have 'display' properties on them, since they are not
> "empty space" on the mode line.

Could you try the patch below and see if gives good results?

diff --git a/src/xdisp.c b/src/xdisp.c
index 6c623ab..5f82ea8 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -27612,15 +27612,28 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
 	      int c = fetch_string_char_advance (mode_string, &i, &i_byte);
 	      if (c == ' ' && prev == ' ')
 		{
-		  display_string (NULL,
-				  Fsubstring (mode_string, make_fixnum (start),
-					      make_fixnum (i - 1)),
-				  Qnil, 0, 0, &it, 0, 0, 0,
-				  STRING_MULTIBYTE (mode_string));
-		  /* Skip past the rest of the space characters. */
-		  while (c == ' ' && i < SCHARS (mode_string))
-		      c = fetch_string_char_advance (mode_string, &i, &i_byte);
-		  start = i - 1;
+		  Lisp_Object prev_pos = make_fixnum (i - 1);
+
+		  if (NILP (Fget_text_property (prev_pos, Qdisplay,
+						mode_string)))
+		    {
+		      display_string (NULL,
+				      Fsubstring (mode_string,
+						  make_fixnum (start),
+						  prev_pos),
+				      Qnil, 0, 0, &it, 0, 0, 0,
+				      STRING_MULTIBYTE (mode_string));
+		      /* Skip past the rest of the space characters. */
+		      while (c == ' ' && i < SCHARS (mode_string)
+			     && NILP (Fget_text_property (make_fixnum (i),
+							  Qdisplay,
+							  mode_string)))
+			{
+			  c = fetch_string_char_advance (mode_string,
+							 &i, &i_byte);
+			}
+		      start = i - 1;
+		    }
 		}
 	      prev = c;
 	    }